Как определить, когда открыто приложение React Native?
My React Native приложение хочет синхронизировать свои локальные данные с API, когда пользователь открывает приложение. Это должно происходить всякий раз, когда пользователь возвращается в приложение, а не только при первом запуске. По сути, я бы хотел, чтобы это был эквивалент обратного вызова AppDelegate applicationDidBecomeActive
, поэтому я могу запустить там код синхронизации. Очевидно, я хотел бы сделать это в React Native.
Насколько я могу судить, обратные вызовы componentWillMount
/componentDidMount
на корневом компоненте выполняются только при первом загрузке приложения, а не после того, как пользователь покидает приложение и возвращается позже (без явного отказа от приложения).
Я думал, что API AppState
предоставит эту функциональность, но его слушатели change
также не запускаются в этом случае.
Это похоже на очевидную функциональность, поэтому я должен пропустить что-то очевидное. Помогите!
Ответы
Ответ 1
Я исправил это, используя AppStateIOS
API вместо AppState
. Более поздние работы, как и ожидалось, на устройствах iOS: когда приложение переходит на задний план, происходит событие "change"
, и снова, когда оно возвращается на передний план. Насколько мне известно, API AppState
, похоже, не запускает событие "change"
на устройстве iOS, как и в случае React Native v0.18. В соглашениях по проектам предполагается, что AppState
должен быть кросс-платформенной оболочкой вокруг AppStateIOS
, но это, похоже, не так.
Следующий пример должен продемонстрировать проблему:
React.createClass({
componentDidMount() {
AppStateIOS.addEventListener('change', state =>
console.log('AppStateIOS changed to', state)
)
AppState.addEventListener('change', state =>
console.log('AppState changed to', state)
)
},
render() {
return <View/>
}
})
Когда этот компонент монтируется в приложение React Native, вы увидите "AppStateIOS изменено на..." при закрытии и открытии приложения. Насколько я знаю, вы никогда не увидите "AppState changed to...".
Обновление
Похоже, что это было исправлено в React Native в последнее время (с v26). Теперь вы можете использовать AppState
, как показано на iOS и Android.
Ответ 2
Я не думаю, что тебе что-то не хватает. Эта функциональность просто не предоставляется реакцией-native из коробки. Возможно, идея заключалась в том, чтобы упростить, поскольку для большинства приложений достаточно выполнить синхронизацию данных, когда приложение вернется на передний план.
Вы можете создать собственный собственный модуль, который предоставляет эту функциональность, или вы можете пойти с простым (вроде хаккой?) решением:
В AppDelegate сохраните ссылку на отредактированный корневой вид:
@interface AppDelegate()
@property (nonatomic, strong) RCTRootView *rootView;
@end
При инициализации представления установите свое свойство и используйте его:
self.rootView = [[RCTRootView alloc] initWithBundleURL:jsCodeLocation
moduleName:@"MyApp"
initialProperties:nil
launchOptions:launchOptions];
Теперь реализуем методы AppDelegate для обработки активного состояния, как в ваших приложениях iOS, и передавайте информацию в качестве реквизита:
-(void)onAppActiveStateChanged:(BOOL)appBecameActive
{
NSMutableDictionary *newProps = [NSMutableDictionary dictionary];
if (self.rootView.appProperties != nil) {
[newProps addEntriesFromDictionary:self.rootView.appProperties];
}
newProps[@"appDidBecomeActive"] = @(appBecameActive);
self.rootView.appProperties = newProps;
}
- (void)applicationWillResignActive:(UIApplication *)application
{
[self onAppActiveStateChanged:NO];
}
- (void)applicationDidBecomeActive:(UIApplication *)application
{
[self onAppActiveStateChanged:YES];
}
На стороне JavaScript сделайте все, что вам нужно, когда изменения реквизита:
componentWillReceiveProps(nextProps) {
if (nextProps.appDidBecomeActive) {
alert('app did become active');
}
}
Я не уверен, что это лучший подход, но он должен работать...
Ответ 3
Думаю, ты уже сам ответил на свой вопрос. Почему бы вам не использовать комбинацию componentWillMount и AppState → 'change'? Это должно охватывать все случаи. Я использую это для синхронизации моего приложения с помощью CodePush.