Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[DatePickerIOS] fails to get the correct value #4787

Closed
unmec opened this issue Dec 15, 2015 · 30 comments
Closed

[DatePickerIOS] fails to get the correct value #4787

unmec opened this issue Dec 15, 2015 · 30 comments
Labels
JavaScript Platform: iOS iOS applications. Resolution: Locked This issue was locked by the bot.

Comments

@unmec
Copy link

unmec commented Dec 15, 2015

Hello there,

I just ran into a curious bug of DatePickerIOS(at least I believe so).

It fails to reflect the correct value(sometimes), here is how I reproduce it:

  • add a console.log of date props in onDateChange;
  • set mode of DatePickerIOS to "time";
  • now scroll the hours' picker for just 1 or 2, then quickly scroll the minutes' picker, I can observe in console that the minutes remain as the previous selected value(sometimes).

A small(big and slow actually) gif to show what happend..

bug

@facebook-github-bot
Copy link
Contributor

Hey macelii, thanks for reporting this issue!

React Native, as you've probably heard, is getting really popular and truth is we're getting a bit overwhelmed by the activity surrounding it. There are just too many issues for us to manage properly.

  • If you don't know how to do something or not sure whether some behavior is expected or a bug, please ask on StackOverflow with the tag react-native or for more real time interactions, ask on Discord in the #react-native channel.
  • If this is a feature request or a bug that you would like to be fixed, please report it on Product Pains. It has a ranking feature that lets us focus on the most important issues the community is experiencing.
  • We welcome clear issues and PRs that are ready for in-depth discussion. Please provide screenshots where appropriate and always mention the version of React Native you're using. Thank you for your contributions!

@skevy skevy added Platform: iOS iOS applications. JavaScript labels Dec 15, 2015
@christopherdro
Copy link
Contributor

@macelii I'm can't reproduce this on master using the UIExplorer example project.
Could you share some of your code or create a example on www.rnplay.org?

@unmec
Copy link
Author

unmec commented Dec 17, 2015

I reproduced the issue with simple code base.
I am on RN 0.11

'use strict';

var React = require('react-native');
var {
  AppRegistry,
  DatePickerIOS,
  StyleSheet,
  Text,
  View,
} = React;

var chosenDate;

var datepicker = React.createClass({

  getDefaultProps: function () {
    return { 
      date: new Date(),
    }; 
  },

  getInitialState: function() { 
    return { 
      date: this.props.date, 
    }; 
  },

  onDateChange: function(date) { 
   this.setState({date: date}); 
   chosenDate = date;
   console.log('selected time is ' + chosenDate);
   },

  render: function() {
    return (
      <View style={styles.container}>
        <Text style={styles.welcome}>
          Welcome to React Native!
        </Text>
        <Text style={styles.instructions}>
          To get started, edit index.ios.js
        </Text>

        <DatePickerIOS
          date = {this.state.date}
          mode = "time"
          onDateChange = {this.onDateChange} />

        <Text style={styles.instructions}>
          Press Cmd+R to reload,{'\n'}
          Cmd+D or shake for dev menu
        </Text>
      </View>
    );
  }
});

@unmec
Copy link
Author

unmec commented Dec 17, 2015

Opps, looks like it runs well with the code above, I need more time to digg in my project to check if there is something wrong, will get back here when I find something

@christopherdro
Copy link
Contributor

@macelii I tried last night as wasn't able to reproduce this.

Closing this for now. Feel free to open it again if the issue comes back.

@abc123s
Copy link

abc123s commented Jul 19, 2016

I know this issue has already been closed, but I wanted to add that I'm also experiencing this bug, and can provide more detail about how to reproduce the issue.

In regular use, it only occurs very occasionally, which is why it may have been difficult to reproduce; however, I can describe in more detail how I've gotten it to occur with some consistency:

  1. Momentum scroll any segment of the date picker
  2. Wait for the segment to stop spinning so that "onDateChange" is called, and immediately...
  3. ...momentum scroll the same segment or another segment (my guess is this second scroll needs to happen while the first onDateChange is running, i.e. immediately after app registers that a new date has been selected)
  4. "onDateChange" will not be called at the completion of 3.

This will leave the app in a state where the DatePickeriOS shows a different date and/or time than expected.

I've tried tracing the error, and it seems to be occurring all the way at the native level; in RCTDatePicker.m, the didChange function is not being called at (4) either.

@chrisbianca
Copy link

I'm seeing this as well, though not sure whether it's this exactly or #8169.

Ultimately you end up being left with a stale date, though for me I'm receiving the onDateChange event in the JS code but with the previous value.

@JakeRawr
Copy link
Contributor

JakeRawr commented Oct 25, 2016

@christopherdro Can we reopen this issue?

This is still a problem. as @chrisbianca suggested. onDateChange as called, but wrong value is returned. maybe take a look at what @abc123s is suggesting?

[Edit]
RN: v0.34
Platform: iOS

I've checked v0.35 and v0.36, this issue is not addressed

@unmec
Copy link
Author

unmec commented Oct 25, 2016

Just to share a workaround(kind of) that I've used in my project:

I added an completely transparent layer on top of my view when user scrolls the pin, this layout will dismiss in 0.8sec, then user will be able to scroll another pin...

It's not elegant, but at least with much less chance for user to pick a wrong value. :-(

@tuananhtd
Copy link

I also ran into this issue. Can be reproduced quite easily like @macelii mentioned in the first post.
Is there anyway we can get the native props?

@chrisknepper
Copy link
Contributor

chrisknepper commented Nov 11, 2016

I am able to reproduce this using the DatePickerIOS demo app on the RN docs and it definitely seems related to momentum scrolling and particularly when the user begins scrolling one section (such as the day) while another is still scrolling (such as the month), or immediately afterwards.

I have recorded a video of this bug in action: http://webmshare.com/ZXyKJ

The beginning I'll attribute to simulator lag, but the bug is definitely noticeable from 23 seconds until the end of the video: the bottom DatePickerIOS instance reads December 24, 2016, but the date variable in the state (at the top) reads December 25, 2016.

@kesyn
Copy link

kesyn commented Jan 14, 2017

+1

@rdagger
Copy link

rdagger commented Feb 14, 2017

I'm experiencing the same problem. The onDateChange event doesn’t always get passed the selected date. Specifically if you spin the day wheel and then push it slightly right as it is stopping. This can have very negative consequences since the user thinks they chose the correct date but the program stores a different date. The problem might be more prevalent on slower devices.

@manishtpatel
Copy link

+1 onDateChange doesn't fire in certain situations, tested with version 0.43, lot of reproduction detail in the thread so not adding it.

I hope i can contribute to resolve this but have no iOS experience, it is puzzling that such a core piece of functionality is buggy and no one from core team is looking into it. Not sure where the priorities are.

@hramos
Copy link
Contributor

hramos commented Jul 20, 2017

Hi there! This issue is being closed because it has been inactive for a while. Maybe the issue has been fixed in a recent release, or perhaps it is not affecting a lot of people. Either way, we're automatically closing issues after a period of inactivity. Please do not take it personally!

If you think this issue should definitely remain open, please let us know. The following information is helpful when it comes to determining if the issue should be re-opened:

  • Does the issue still reproduce on the latest release candidate? Post a comment with the version you tested.
  • If so, is there any information missing from the bug report? Post a comment with all the information required by the issue template.
  • Is there a pull request that addresses this issue? Post a comment with the PR number so we can follow up.

If you would like to work on a patch to fix the issue, contributions are very welcome! Read through the contribution guide, and feel free to hop into #react-native if you need help planning your contribution.

@hramos hramos added the Icebox label Jul 20, 2017
@hramos hramos closed this as completed Jul 20, 2017
@ghost
Copy link

ghost commented Aug 13, 2017

I'm also noticing this, if you spin the wheel fast it can sometimes not register any events.

@ammichael
Copy link

It is really frustrating how something as basic as getting the date from the DatePicker doesn't work as expected :(

My app depends on the notifications, and right now I can't really rely on this component.

Any suggestion?

@unmec
Copy link
Author

unmec commented Aug 14, 2017

I moved my projects to RN 0.39 eight months ago, and I am still using my trick with transparent layer as the problem persists.

@SudoPlz
Copy link
Contributor

SudoPlz commented Oct 22, 2017

Problem still exists in 0.49 as well....

@alindj
Copy link

alindj commented Oct 27, 2017

I am also facing this issue with latest build.

@shazvi
Copy link

shazvi commented Oct 31, 2017

I had this same issue as well. In the end, what worked for me was to include the timeZoneOffsetInMinutes attribute to the DatePickerIOS component:

  <DatePickerIOS
      date = {this.state.date}
      mode = "time"
      onDateChange = {this.onDateChange} 
      timeZoneOffsetInMinutes={(new Date()).getTimezoneOffset()*-1}/>

Make sure to multiply timezone offset by -1

@dluksza
Copy link

dluksza commented Nov 3, 2017

Can anyone confirm that workaround from @shazvi works?

@SudoPlz
Copy link
Contributor

SudoPlz commented Nov 3, 2017

I don't think it works. I'm always including timeZoneOffsetInMinutes because I needed it there to actually set the timezone, and I still get that problem.

@sjyoung12
Copy link

PSA: I fixed this by writing a custom DatePickerIOS bridge, which is identical to the RN core bridge but with this modification to RCTDatePicker.m:

- (void)didChange
{
  // Invoke `_onChange` asynchronously on the main queue to circumvent the "stale date" bug.
  // https://github.com/facebook/react-native/issues/8169
  // https://github.com/facebook/react-native/issues/4787
  if (_onChange) {
    // Use a weak reference to `self` to avoid a retain cycle.
    __weak __typeof__(self) weakSelf = self;
    dispatch_async(dispatch_get_main_queue(), ^{
      _onChange(@{ @"timestamp": @(weakSelf.date.timeIntervalSince1970 * 1000.0)});
    });
  }
}

Hope this helps!

@SudoPlz
Copy link
Contributor

SudoPlz commented Nov 3, 2017

@sjyoung12 I'm a bit confused. Did you fork react-native and changed DatePickerIOS or did you create a native UI component (or something else?) in order to make this change?

@sjyoung12
Copy link

@SudoPlz: the latter.

@unmec
Copy link
Author

unmec commented Nov 4, 2017

@sjyoung12 commented (#4787 (comment) "2017-11-03T16:24:24Z - Replied by Github Reply Comments"):

PSA: I fixed this by writing a custom DatePickerIOS bridge, which is identical to the RN core bridge but with this modification to RCTDatePicker.m:

- (void)didChange
{
  // Invoke `_onChange` asynchronously on the main queue to circumvent the "stale date" bug.
  // https://github.com/facebook/react-native/issues/8169
  // https://github.com/facebook/react-native/issues/4787
  if (_onChange) {
    // Use a weak reference to `self` to avoid a retain cycle.
    __weak __typeof__(self) weakSelf = self;
    dispatch_async(dispatch_get_main_queue(), ^{
      _onChange(@{ @"timestamp": @(weakSelf.date.timeIntervalSince1970 * 1000.0)});
    });
  }
}

Hope this helps!

Tested and it works, many thanks!

@unmec
Copy link
Author

unmec commented Nov 8, 2017

Update:
It's far more reliable with @sjyoung12 way to bridge. In extremely rare cases(when users scroll the pins like crazy all day long) there is chance problem still occur but I think normal users won't do that.

tomekszeliga added a commit to tomekszeliga/react-native that referenced this issue Nov 8, 2017
tomekszeliga added a commit to tomekszeliga/react-native that referenced this issue Nov 9, 2017
@Looveh
Copy link

Looveh commented Dec 19, 2017

I'm still experiencing this issue. A hotfix that worked for us was to monkey patch the didChange method on RCTDatePicker to delay by 5ms before sending the change event to JS, during which time the value of the date has had time to reflect the one shown in the interface.

Attaching our code here (you can observe the time disparity yourself by uncommenting the two log statements):

// RCTDatePicker+Delay.h

#import <React/RCTDatePicker.h>

@interface RCTDatePicker (Delay)

@end

// RCTDatePicker+Delay.m

#import "RCTDatePicker+Delay.h"
#import <React/UIView+React.h>

@interface RCTDatePicker ()

@property (nonatomic, copy) RCTBubblingEventBlock onChange;

@end

@implementation RCTDatePicker (Delay)

- (void)didChange
{
  // NSLog(@"didChange 1 %@", self.date);
  dispatch_time_t delay = dispatch_time(DISPATCH_TIME_NOW, NSEC_PER_SEC * 0.05);
  dispatch_after(delay, dispatch_get_main_queue(), ^(void){
    // NSLog(@"didChange 2 %@", self.date);
    if (self.onChange) {
      self.onChange(@{ @"timestamp": @(self.date.timeIntervalSince1970 * 1000.0) });
    }
  });
}

@end

@iberrasDomandtom
Copy link

iberrasDomandtom commented Dec 20, 2017

Hey @sjyoung12 did you upload your native wrapper? I cannot find any useful guide to create a native Ui Wrapper component. If you have the whole code, that would be great!

timothyej added a commit to blockfirm/bithodl-app that referenced this issue Jan 24, 2018
This commit work arounds a bug that causes the DatePicker to return
an incorrect date. This is a known bug with the DatePickerIOS component
(and perhaps even in iOS).

The workaround is to use a modified component that exposes a getter
to get the date instead of relying on events/callbacks.

Read more about the issue here:
facebook/react-native#4787
facebook/react-native#8169
@facebook facebook locked as resolved and limited conversation to collaborators Jul 20, 2018
@react-native-bot react-native-bot added the Resolution: Locked This issue was locked by the bot. label Jul 20, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
JavaScript Platform: iOS iOS applications. Resolution: Locked This issue was locked by the bot.
Projects
None yet
Development

No branches or pull requests