Реагировать — Переход к одному и тому же компоненту странное поведение

#react-native #navigation #state #render

Вопрос:

Я ломаю голову над этим, поведение, которое я вижу, кажется мне странным, хотя для некоторых из вас это может иметь смысл.

Рассмотрим этот компонент:

 const DishPreparation = ({ dish }) => {
  const [slideIndex, setSlideIndex] = useState(0)
  const sceneRef = useRef(null)
  useKeepAwake();

  return (
    <View style={styles.scene} ref={sceneRef}>
      <View flex={0.12} style={{ marginTop:-10 }}>
        <ProgressSteps activeStep={slideIndex} activeStepIconBorderColor={colors.lightTan} completedProgressBarColor={colors.lightTan} completedStepIconColor={colors.lightTan}>
          {dish.preparationSteps.map((step, index) => (
            <ProgressStep removeBtnRow key={index}/> ))}
        </ProgressSteps>
        ......
  )
 

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

Допустим , в первом блюде было 3 элемента dish.preparationSteps , а во втором-4, затем dish.preparationSteps.map(step, index) возвращается только 3 элемента вместо 4, но если я визуализирую step.someInfo внутри отображения, то я действительно вижу новые значения блюда.

Как это происходит? Я бы ожидал, что будут возвращены либо 4 элемента, либо 3 элемента, но со старыми значениями блюда, как происходит эта смесь? Кроме того, не знаю, помогает ли это, но slideIndex сохраняет свое старое значение и не инициализируется заново до 0.

Вот как я перемещаюсь по плавающему компоненту:

 navigation.navigate('Tabs', {
                        screen: 'Home',
                        params: { screen: 'Dish', params: { from: '', data: dish } },
                      })
 

Вот как я перехожу к нему через какой-то другой компонент(который работает так, как ожидалось)

 navigation.push('Dish', {from: 'DishList', data: item})
 

Если потребуется какой-либо другой код, я буду рад его добавить.

Комментарии:

1. не могли бы вы предоставить рабочий пример с минимальным кодом через github или expo snack?

Ответ №1:

При использовании .navigate вместо .push навигация будет искать это имя экрана («Блюдо») и просто изменять параметры навигации, не перемонтируя компонент или не открывая с его помощью новый экран. Обычно вы можете просто использовать navigation.push (как в вашем последнем примере), но проблема в том, что вы пытаетесь перемещаться с помощью навигатора верхнего уровня. Вы не можете использовать .нажмите туда, потому что это приведет к внешнему навигатору, у которого нет экрана «Тарелка». Если вы хотите добавить еще один экран «Тарелка» поверх существующего во вложенном навигаторе, вам необходимо выполнить навигацию.нажмите из навигатора стека, в котором вы хотите перемещаться; дело только в том, что ваш плавающий не находится в этом навигаторе стека

Первое, что вы можете попробовать, это добавить уникальное key изображение на свой экран при навигации, например

 navigation.navigate('Tabs', {
  screen: 'Home',
  params: { screen: 'Dish', key: dish.id, params: { from: '', data: dish } },
})
 

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

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

И еще лучшим решением было бы не пытаться перемещаться внутри внутренних навигаторов от внешних навигаторов

Комментарии:

1. Первое решение, к сожалению, не работает, если я перейду от блюда с большим количеством подготовительных шагов к блюду с меньшим количеством, оно выдаст ошибку undefined (попытка связаться с реквизитами.дети[i] для i, которого не существует. Такое же поведение, как и без уникального ключа..

2. В своем втором решении вы имели в виду что-то подобное? navigation.navigate('Tabs', {screen:'Home'}); navigation.push('Dish', {from: '', data: dish})}; ? Потому что это работает для меня, просто не уверен, хорошая ли это практика или нет

3. 1. попытайтесь выяснить, в чем дело (почему вы пытаетесь связаться с реквизитом.дети? в компоненте экрана нет детей) 2. нет, вы предлагаете просто позвонить .перейдите, а затем .нажмите. На странице, на которую я ссылался, есть примеры диспетчеризации навигационных действий

4. 1. Я не.. это компонент ProgressSteps , который пытается достичь каждого ProgressStep возвращенного с помощью сопоставления, это компонент с github, но это означает, что он все еще использует старое состояние.. 2. Я просто хотел убедиться, что я изучу его

Ответ №2:

Может быть, реквизит getId — это то, что вы ищете?

Из документов навигации React:

В навигаторе стека вызов navigate с именем экрана приведет к другому поведению, основанному на том, присутствует ли экран уже или нет. Если экран уже присутствует в истории стека, он вернется на этот экран и удалит все экраны после этого. Если экрана нет, он запустит новый экран.

Вместо этого вы можете использовать опору getId, чтобы нажать на новый экран. Например, допустим, вы указали реквизит getId для экрана профиля:

 <Screen name={Profile} component={ProfileScreen} getId={({ params }) => params.userId} />
 

Теперь, если у вас есть стек с историей Home > Profile (userId: bob) > Settings , и вы вызовете navigate(Profile, { userId: 'alice' }) результирующие экраны Home > Profile (userId: bob) > Settings > Profile (userId: alice) , так как он добавит новый Profile экран, так как соответствующий экран не был найден.