反应本机:使用上下文将子状态挂接到父状态

时间:2020-06-15 11:31:15

标签: reactjs react-native react-hooks

我正在尝试在 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>
  )
}

2 个答案:

答案 0 :(得分:1)

userContext value发生更改时,您需要通过添加state.users作为useMemo的依赖项来重新创建state.users,否则上下文值将保持对值的相同引用并记录触发器更改所有听众

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
  });

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

答案 1 :(得分:1)

您需要根据useContext的更改重新评估state.users

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