Мы наблюдаем странное поведение в нашем приложении 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"
}
}