Реагируйте на навигационные крепления с предыдущими навигационными параметрами, затем с новыми - PullRequest
0 голосов
/ 07 мая 2018

Мы наблюдаем странное поведение в нашем приложении React Native + React Navigation, поэтому мы создали простой пример для демонстрации.

У нас есть 2 экрана: A и B.

На экране A есть две кнопки, каждая из которых перемещается на экран B. Первая кнопка передает идентификатор параметра: 1, вторая передает идентификатор: 2.

На экране B мы консоль регистрируем входящий параметр как в методе render (), так и в методе componentDidMount ().

Если я нажму кнопку с идентификатором: 1 на экране A, выходной параметр на экране B будет исправлен и записан как id: 1 как в render (), так и componentDidMount (). Однако, если я затем вернусь назад и очень быстро нажму кнопку с идентификатором 2: записанный вывод сначала будет показан как идентификатор: 1, а затем как идентификатор: 2. В следующем порядке:

Первый щелчок:

рендер: 1

componentDidMount: 1

(потом обратно, потом быстро :)

Второй щелчок

рендер: 1

рендер: 2

componentDidMount: 1

componentDidMount: 2

Казалось бы, призрак ранее смонтированного компонента все еще преследует наше приложение. Более того, это похоже на состояние гонки, потому что вам нужно быстро щелкнуть, чтобы вызвать призрака, медленный щелчок не вызовет такое поведение.

Вот и вся заявка:

import React from 'react'
import { View, Text, TouchableOpacity } from 'react-native'
import { StackNavigator } from 'react-navigation'
class ScreenA extends React.Component {
  render() {
    const { navigation } = this.props;
    return (      
      <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
        <TouchableOpacity style={{ marginVertical: 12, padding: 32, borderWidth: 1 }} 
          onPress={() => { navigation.navigate( 'ScreenB', { id: 1 })}}>
          <View style={{ }}><Text>Button 1</Text></View>
        </TouchableOpacity>
        <TouchableOpacity style={{ marginVertical: 12, padding: 32, borderWidth: 1 }} 
          onPress={() => { navigation.navigate( 'ScreenB', { id: 2 })}}>
          <View style={{ }}><Text>Button 2</Text></View>
        </TouchableOpacity>
      </View>
    )
  }
}
class ScreenB extends React.Component {
  componentDidMount(){
    console.log('%c componentDidMount: '+this.props.navigation.state.params.id, 'padding: 2px; background: blue; color: #fff')
  }
  render() {
    console.log('%c render: '+this.props.navigation.state.params.id, 'padding: 2px; background: green; color: #fff')
    return (   
      <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
        <TouchableOpacity style={{ padding: 16 }} onPress={() => this.props.navigation.goBack()}>
          <View style={{ }}><Text>Button</Text></View>
        </TouchableOpacity>        
      </View>
    )
  }
}
const Router = StackNavigator({
  ScreenA: { screen: ScreenA },
  ScreenB: { screen: ScreenB }
})
export default class App extends React.Component {
  render() {
    return (
      <Router />
    )
  }
}

Также здесь есть закуска:

https://snack.expo.io/@makerepeat/navigation-bugs

... и package.json:

{
  "name": "rn2-test2",
  "version": "0.1.0",
  "private": true,
  "devDependencies": {
    "react-native-scripts": "1.14.0",
    "jest-expo": "~27.0.0",
    "react-test-renderer": "16.3.1"
  },
  "main": "./node_modules/react-native-scripts/build/bin/crna-entry.js",
  "scripts": {
    "start": "react-native-scripts start",
    "eject": "react-native-scripts eject",
    "android": "react-native-scripts android",
    "ios": "react-native-scripts ios",
    "test": "jest"
  },
  "jest": {
    "preset": "jest-expo"
  },
  "dependencies": {
    "expo": "^27.0.1",
    "react": "16.3.1",
    "react-native": "~0.55.2",
    "react-navigation": "^1.5.12"
  }
}

1 Ответ

0 голосов
/ 07 мая 2018

Проблема в том, как работает navigation.navigate.Если вы используете его, не передавая ключ для следующего экрана, react-navigation не будет соответствовать ему с уже установленным экраном, следовательно, монтирует еще один.

То, что вы можете наблюдать здесь, это как раз тот случай, когдаКомпонент еще не был размонтирован, но навигация не знает этого и отображает другой экземпляр того же компонента.

Это можно предотвратить, передав параметр ключа в navigate функцию следующим образом:

navigation.navigate({routeName: 'ScreenB', key: 'ScreenB', params: { id: 1}})

navigation.navigate({routeName: 'ScreenB', key: 'ScreenB', params: { id: 2}})

Теперь StackNavigator может проверить, существует ли уже экран с таким же ключом, и запретить его монтаж.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...