Как создать глобальное состояние в React Native?

#react-native #react-hooks #use-state #react-state

Вопрос:

Надеюсь, у тебя все отлично получается 🙂

Я работаю над функцией «Любимый экран», где я хочу добавить понравившиеся упражнения на этот экран. Все прошло идеально, моя проблема в том, что экраны не отображаются повторно при нажатии кнопки, а только при повторном рендеринге приложения. Вот пользовательский крючок:

  const useStorage = (name, id, pratice, navigation) => {

  const [favorites, setFavorites] = useState();

  const { storageDB } = useContext(StorageContext);

 
  //Favorites Actions
  const getFavorites = () => {
    const checkFavorites = storageDB.map((store) =>
      store.exercises.filter((exArray) => exArray.favorite)
    );
    const favoritesResult = checkFavorites.filter((ex) => ex.length !== 0);
    if (favoritesResult.length !== 0) return setFavorites(favoritesResult);
    return null;
  };

  const toggleFavorite = () => {
    //Find exercise
    const exerciseIndex = storageDB[topicIndex()].exercises.findIndex(
      (ex) => ex.id === id
    );

    //Topic > Exercise
    const exercise = storageDB[topicIndex()].exercises[exerciseIndex];

    //Toogle favorite
    exercise.favorite = !exercise.favorite;

    //Store in AsyncStorage
    storage.storeData(storageDB);
  };

  useEffect(() => {
    getFavorites();
  }, []);

  return {
    storageDB,
    getFavorites,
    toggleFavorite,
    favorites
  };
};
export default useStorage;
 

Параметры крючка предназначены для правильного выполнения упражнения в хранилище и вызываются один раз в getFavorites().

Вот любимый экран:

 const FavoritesScreen = () => {
  const { favorites } = useStorage();

  const Favorites = () => {
    if (favorites)
      return favorites.map((exArray) =>
        exArray.map((ex) => (
          <Card
            key={ex.id}
            exercise={ex}
            topicName={ex.topicName}
            onPress={() =>
              navigation.navigate("ExerciseDetails", {
                exercise,
                name: ex.topicName
              })
            }
          />
        ))
      );
    return <NotFound text="No favorite exercises" noImage />;
  };

  return (
    <Screen>
      <Image source={require("../assets/favorites.png")} style={styles.image} />
      <Title style={styles.title}>Favorites</Title>
      <View style={styles.searchContainer}>
        <SearchInput />
      </View>
      <Container scrollView>
        <Favorites />
      </Container>
    </Screen>
  );
};
 

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

Ответ №1:

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

Например, toggleFavorite не вызывает setFavorites, поэтому это не приведет к повторному показу экрана, если вы хотите, чтобы экран был повторно показан, вам нужно будет вызвать setFavorites(newFavourites), где newFavorites имеет другую ссылку на текущие избранные.

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

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

1. Эй, Адам! Извините, что не добавил больше кода, но я беспокоился о том, чтобы загрязнить сообщение слишком большим количеством информации. Проект запутан переменными useContext, пользовательскими связями с событиями AsyncStorage, что немного запутанно, чтобы поместить все здесь. Но ты прав. Благодаря тебе я все понял! Я опубликую решение. Спасибо вам за сочувствие! 🙂

Ответ №2:

Поток, который я намеревался, был:

  1. Когда пользователю нравится упражнение:

введите описание изображения здесь

  1. Объект упражнения обновляется в локальном хранилище и передается на экран Избранное:

введите описание изображения здесь

Моя проблема заключалась в том, что, когда пользователю не нравилось упражнение, оно не обновляло оба компонента («Счастье» и «Избранное»). Я решил эту проблему с помощью navigation.addListenter и создания локального состояния для избранного экрана (как упоминал Адам).

Вот строка в Избранном:

  useEffect(() => {
    navigation.addListener("focus", () => setFavorites(updatedFavorites()));
  }, []);
 

Вот линия счастья:

 useEffect(() => {
    navigation.addListener("focus", () => setKey((prevKey) => prevKey   1));
  }, []);
 

Теперь каждый раз, когда мы вводим эти компоненты, они будут повторно отображаться, если будут внесены изменения 🙂