【问题标题】:React Native: Hook Child State to Parent's State using ContextReact Native:使用上下文将子状态挂钩到父状态
【发布时间】:2020-06-15 11:31:15
【问题描述】:

我正在尝试在 ChildScreen 中重新渲染 {userNumbers}。我设法在 Home 中添加了userNumbers 状态,但它不会重新呈现文本。

UserContext.js

import { createContext } from 'react';

export const UserContext = createContext(null);

Home.js

import React from 'react';
import { createStackNavigator } from '@react-navigation/stack';
import { UserContext } from "../contexts/UserContext";
import ChildScreen from "ChildScreen";

const Stack = createStackNavigator();

export default function Home() {
  const [state, dispatch] = React.useReducer((prevState, action) => {
    switch (action.type) {
      case 'ADD_USER':
        return {
          ...prevState,
          users: state.users + action.newUsers
        };
    }
  }, {
    users: 0
  });

  const userContext = React.useMemo(
    () => ({
      addUsers: async data => {
        dispatch({
          type: 'ADD_USER',
          newUsers: data.newUsers
        });
      },
      userNumbers: state.users
    }),
    []
  );

  return (
    <UserContext.Provider value={userContext}>
      <Stack.Navigator>
        <Stack.Screen name="ChildScreen" component={ChildScreen} />
      </Stack.Navigator>
    </UserContext>
  )
}

ChildScreen.js

import React from 'react';
import { View, Text } from 'react-native';
import { TouchableWithoutFeedback } from 'react-native-gesture-handler';
import { UserContext } from "../contexts/UserContext";

export default function ChildScreen() {
  const { addUsers, userNumbers } = React.useContext(UserContext);

  render (
    <View><Text>{userNumbers}</Text></View>
    <TouchableWithoutFeedback onPress={() => { addUsers({newUsers: 999)}) }>
      <Text>Add 999 Users</Text>
    </TouchableWithoutFeedback>
  )
}

【问题讨论】:

    标签: reactjs react-native react-hooks


    【解决方案1】:

    state.users 更改时,您需要重新创建userContext value,方法是将state.users 添加为useMemo 的依赖项,否则您的上下文值将保持相同的值引用,并会注意到任何侦听器的触发器更改

    const userContext = React.useMemo(
        () => ({
          addUsers: data => {
            dispatch({
              type: 'ADD_USER',
              newUsers: data.newUsers
            });
          },
          userNumbers: state.users
        }),
        [state.users] // Add a dependency here so that user update changes reference
      );
    

    你还应该将你的 reducer 定义为纯的,即它不应该使用闭包状态

    const [state, dispatch] = React.useReducer((prevState, action) => {
        switch (action.type) {
          case 'ADD_USER':
            return {
              ...prevState,
              users: prevState.users + action.newUsers // use prevState here
            };
        }
      }, {
        users: 0
      });
    

    附:您无需将addUsers 函数定义为asyncdispatch 异步发生,但需要重新渲染才能生效,您无需等待

    【讨论】:

    • 谢谢。顺便说一句,为什么state 还在[state, dispatch] 中?以后会用吗?
    • 为了让组件更干净,你应该在组件之外定义reducer。
    • 是的,我自己也搞糊涂了。
    • 我从&lt;Add /&gt; 按钮调用addUsers()。当我单击时,所有“添加”按钮都会重新呈现,这是意料之外的。我只想重新渲染单击的按钮。这发生在我添加 state.users 作为依赖项之后,但我需要听用户数。请指教。
    【解决方案2】:

    您需要重新评估useContext 上的state.users 更改:

    const userContext = React.useMemo(
      () => ({
        //...
        userNumbers: state.users,
      }),
      [state.users]
    );
    

    【讨论】:

    • 顺便说一句,我的 onPress 按钮更新了两个值:一个是本地状态,另一个是这个用户上下文状态值。通过添加这个state.users 依赖,重新渲染本地状态的文本变得更慢。我知道这是一个折衷方案,但您有什么建议可以让当地状态的文本更快吗?
    • 原来所有按钮组件都通过添加 state.users 依赖项重新呈现,这不是预期的。知道如何仅重新渲染单击的按钮吗?
    猜你喜欢
    • 1970-01-01
    • 2019-03-08
    • 2019-04-01
    • 2021-03-22
    相关资源
    最近更新 更多