Вызовите функцию, которая использует хуки, из пользовательского заголовка реакции-навигации - PullRequest
0 голосов
/ 05 февраля 2020

У меня есть экран, написанный с помощью React Hooks. На экране у меня есть пользовательская кнопка в заголовке реакции-навигации. При нажатии на кнопку мне нужно вызвать функцию updateUser, которая использует значения из состояния (например, userName).

Поэтому я передаю функцию updateUser в заголовок с функцией navigation.setParams. В шапке я звоню updateUser из navigation.state.params.

При первом нажатии - значение userName правильное. Но если я затем изменю значение userName изнутри компонента - когда я нажимаю кнопку, значение внутри функции остается неизменным.

Вот пример кода:

const ProfileScreen = ({navigation}) => {
 const [userName, setUserName] = useState('John');

  useEffect(() => {
    navigation.setParams({
      updateUser,
    });
  }, [])

  const updateUser = () => {
    console.log('userName', userName);
  }

  return (...)
};
ProfileScreen.navigationOptions = ({navigation}) => ({
  headerRight: () => {
    const {params = {}} = navigation.state;
    return (
      <TouchableOpacity onPress={() => params.updateUser()}>
        <Text>Update user</Text>
      </TouchableOpacity>
    );
  },
});

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

Есть ли какой-нибудь правильный способ ее решения? Если нет, то какой обходной путь?

1 Ответ

0 голосов
/ 05 февраля 2020

Мой обходной путь # 1 заключается в использовании еще одного useState, который отслеживает, нажата ли кнопка Обновить.

Таким образом, в заголовке при нажатии кнопки мы устанавливаем isUpdateButtonPressed к истине. Затем в компоненте мы наблюдаем за этим изменением, а если оно меняется - мы вызываем updateUser. Таким образом, состояние внутри функции updateUser является правильным.

const ProfileScreen = ({navigation}) => {
  const [userName, setUserName] = useState('John');
  const [isUpdateButtonPressed, setIsUpdateButtonPressed] = useState(false);

  useEffect(() => {
    navigation.setParams({
      setIsUpdateButtonPressed,
    });
  }, [])

  useEffect(() => {
    if (isUpdateButtonPressed) {
      updateUser();
      setIsUpdateButtonPressed(false);
    }
  }, [isUpdateButtonPressed]);

  const updateUser = () => {
    console.log('userName', userName);
  }
};
ProfileScreen.navigationOptions = ({navigation}) => ({
  headerRight: () => {
    const {params = {}} = navigation.state;
    return (
      <TouchableOpacity onPress={() => params.setIsUpdateButtonPressed(true)}>
        <Text>Update user</Text>
      </TouchableOpacity>
    );
  },
});

Мой обходной путь # 2 должен был использовать useEffect для отслеживания всех переменных, используемых в функции updateUser и Вызывайте navigation.setParams с обновленной функцией updateUser каждый раз, когда изменяются эти переменные:

  useEffect(() => {
    navigation.setParams({
      updateUser,
    });
  }, [userName])

Хотя решение # 2 немного чище в коде, лично я предпочитаю решение # 1, так как второе может привести к очевидные ошибки в случае, если мы пропустили добавление некоторой переменной, которая используется в функции updateUser, для использования массива Effect.

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