Как очистить состояние в компоненте класса в React Native?

Я новичок в React Native и изо всех сил пытаюсь очистить состояние экрана.

Например, экран A имеет некоторые состояния --> экран B, вернемся к экрану A, старые состояния очищены. Я использую React Navigation V5.

Я пытаюсь сделать следующее:

  1. После перехода от MainMap.js к последнему экрану TripsListScreen.js (весь процесс представляет собой стек из 4 экранов, вложенных в ящик), я получил все данные, хранящиеся в хранилище Redux, и отобразил их в TripsListScreen.
  2. Проблема в том, что когда я нажимаю кнопку add в TripsListScreen, чтобы вернуться в MainMap.js, она не очищает каждое состояние, как я ожидал.

Вот состояния MainMap.js :

const initialState = {
    hasMapPermission: false,
    _userLocationDisplayed: null,
    userLatitude: 0,
    userLongitude: 0,
    initial_UserLatitude: 0,
    initial_UserLongitude: 0,
    userLocationAddress: '',

    destination: [],
    destinationName: [],
    destinationAddress: [],
    destinationCoords: [],
    destinationImageUri: [],

    numOfInput:[0,1],
    counter: 1,
    wayPoints: [],
    markers: [],
}

class MainMap extends React.Component{

    constructor(props){
        super(props);

        this.state = initialState;


    };


    componentDidMount(){
        console.log('Hello',this.props)
        if(this.props.route.params === true){
            this.setState(initialState)
        }
        this._requestUserLocation();
    };

По сути, я попытался передать логический параметр от TripsListScreen до MainMap, и если параметр верен, я верну все состояния в начало. Однако это не работает так, как ожидалось.

Вот TripsListScreen:

//...
<Layout style={styles.bottom}>
      <TouchableOpacity onPress={() => props.navigation.navigate('PlanningProcess', {
            screen: 'MainMapScreen',
            params: {doAddPlace: true}
      })} style={styles.createTrip}>
          <Layout style={styles.button} >
               <Icon name='add' size={35} />
          </Layout>
      </TouchableOpacity>
</Layout>
//...

Вот навигация:

  1. StackNavigators:
const Stack = createStackNavigator();

const StackNavigator = (props) => {
    return(
        <Stack.Navigator screenOptions={{headerShown: false}}>
            <Stack.Screen name='MainMapScreen' component={MainMap} />
            <Stack.Screen name='TripDescription' component={TripDescription} />
            <Stack.Screen name='TripsListDetailScreen' component={TripsListDetailScreen} />
            <Stack.Screen
                name='TripsListScreen' 
                component={TripsListScreen} 
                options={{
                    headerLeft: () => (<Icon style={{marginHorizontal: 30, marginTop: 30}} color='white' name='menu' size={30} onPress={() => props.navigation.dispatch(DrawerActions.openDrawer())}/>),
                    title:'Something'
                    }}
            />
        </Stack.Navigator>
    );
};
export default StackNavigator;
  1. Основное Navigators:
const Navigator = () => {

    return(
        <NavigationContainer>
            <Drawer.Navigator
                statusBarAnimation='slide'
                drawerContent={props => 
                    <DrawerContent {...props} />}>
                <Drawer.Screen name='Welcome' component={WelcomeStackScreen}  />
                <Drawer.Screen name='TripsListScreen' component={TripsListScreen} />
                <Drawer.Screen name='PlanningProcess' component={StackNavigators} />
            </Drawer.Navigator>

        </NavigationContainer>
    );
};


export default Navigator;

Вот что отображает MainMap:

Что отображает MainMap

Это то, что я ожидал при переходе от TripsListScreen (для создания новой поездки):

Ожидаемый результат после очистки

ПОЖАЛУЙСТА, ПОМОГИТЕ!!!


person Ken Pham    schedule 27.03.2020    source источник


Ответы (3)


Метод ComponentDidMount() срабатывает только в первый раз при монтировании компонента, и когда вы переходите к новому экрану, предыдущий экран все еще монтируется в стеке.

Если вы хотите повторно инициализировать свое состояние каждый раз, когда ваш компонент получает фокус, вы можете установить прослушиватель на фокус навигации.

Как это,

const unsubscribe = navigation.addListener('willFocus', () => {
      // Do something 
      // re-initialise the state
});
person Anurodh Singh    schedule 28.03.2020
comment
Это потрясающе. Большое спасибо за помощь Anurodh. Кстати, не могли бы вы объяснить мне немного об этом? Как вы можете видеть на изображении выше, эти панели поиска являются компонентом класса PlaceInput ( ‹PlaceInput/›). Итак, как мы можем сбросить все состояния этого PlaceInput одновременно с этим в MainMap ? Пожалуйста, направь меня - person Ken Pham; 28.03.2020
comment
Добро пожаловать! Если вы хотите сбросить компонент <PlaceInput/>, есть несколько способов сделать это: 1. Соедините компонент <PlaceInput/> с избыточностью и перед тем, как вернуться обратно на экран карты, отправьте действие, которое сбрасывает редюсер, который изменяет свойства этого компонента <PlaceInput/> и запускает componenDidUpdated, и в этом методе вы можете сбросить состояние компонента <PlaceInput/>. - person Anurodh Singh; 28.03.2020
comment
2. При переходе на другой экран непосредственно перед вызовом метода навигации вызовите метод компонента <PlaceInput/>, чтобы сбросить состояние компонента <PlaceInput/>. Чтобы вызвать метод дочернего элемента из родительского компонента, вы должны сначала получить ссылку на дочерний компонент. - person Anurodh Singh; 28.03.2020
comment
Удивительный Анурод. Огромное спасибо. Я просто хочу задать еще 1 вопрос. Как мы можем повторно смонтировать компонент после того, как мы его размонтировали? - person Ken Pham; 28.03.2020
comment
Так же, как вы монтируете его в первый раз. Если ваш компонент находится в иерархии рендеринга (в основном в блоке возврата), он будет рендерить (монтировать) и следовать жизненному циклу до тех пор, пока вы не удалите его из рендеринга. на основании каких-либо условий. Всякий раз, когда в будущем вы решите снова вернуть тот же компонент, он будет снова смонтирован. - person Anurodh Singh; 28.03.2020
comment
ТАК будет ли он перемонтироваться, когда я вернусь к нему. Так как я пытался использовать console.log в componentWillMount и componentDidMount в MainMap, но он не появляется. Я сбросил состояние, но запрос, который я сделал в componentWillMount (или даже componentDidMount), не выполняется, когда я возвращаюсь к нему? - person Ken Pham; 28.03.2020
comment
Нет, я только что объяснил жизненный цикл компонента, но в случае навигации, когда вы переходите с экрана A на экран B, он создает стек, например [A, B], оба монтируются один за другим, а когда вы возвращаетесь к A, он просто возвращается к A ( который уже отрендерен) и извлеките экран B из стека, и теперь вы знаете, что A уже отрендерен (смонтирован), поэтому методы componentDidMount не будут вызываться. Однако, если вы намеренно хотите, чтобы компонент, выглядящий по-новому, при переходе от B к A, вы можете попробовать метод push (не рекомендуется) вместо navigate. Та же реализация. - person Anurodh Singh; 28.03.2020
comment
Давайте продолжим обсуждение в чате. - person Ken Pham; 28.03.2020

ComponentDidMount в MainMap.js не срабатывает, потому что экран уже смонтирован. Пожалуйста, посмотрите на эту функция `componentDidMount()` не вызывается после навигации

person Gaston Ferreyra    schedule 28.03.2020
comment
Спасибо за помощь. Я использую реагирующую навигацию v5. Решение по ссылке, которую вы предоставили, устарело. Не могли бы вы предоставить мне обновленные руководства? - person Ken Pham; 28.03.2020

в StackNavigator экраны не размонтируются, когда вы открываете новые экраны поверх них. Таким образом, если вы перейдете от A к B, а затем от B к C, и A, и B останутся установленными. Если вы вернетесь с C на B, C размонтируется. Это как методы push и pop в массиве. componentDidMount в MainMap не вызывается, когда вы возвращаетесь к нему, так как он не размонтируется в первую очередь. Это объясняется здесь Жизненный цикл навигации.

Поскольку вы используете Redux и говорите, что все данные хранятся в хранилище Redux, сделайте так, чтобы ваш компонент MainMap отображался исключительно из данных из хранилища, а не из собственного состояния. Затем вы можете манипулировать этими данными из TripsListScreen, отправляя действия. Проще всего было бы создать что-то вроде действия RESET_MAIN_MAP, которое сбросит эту часть состояния экрана MainMap.

person Max    schedule 28.03.2020
comment
Привет Макс. Ответ очень полезен. Большое спасибо. Но когда я имею в виду хранить все данные в хранилище Redux, я имею в виду после рендеринга MainMap. TheMainMap отображает все на основе собственного состояния (ломаная линия, панели поиска...). - person Ken Pham; 28.03.2020
comment
После рендеринга и поиска пользователями мест все эти места сохраняются в магазине Redux. - person Ken Pham; 28.03.2020
comment
Чего я хочу добиться, так это того, что все состояния MainMap.js размонтированы после того, как я перейду к нему из TripsListScreen. Если проблема в Stack Navigator, можете ли вы предложить мне какие-то альтернативы? - person Ken Pham; 28.03.2020