我正在使用React Context,并想确认我的结构

时间:2019-06-24 23:05:44

标签: reactjs react-hooks react-context

这是我的第一个使用带有钩子的react上下文而不是react-redux的应用程序,希望获得应用程序结构的帮助。 (我不使用react-redux或redux-saga库。)

  • 上下文
const AppContext = createContext({
  client,
  user,
});
  • 动作示例之一
export const userActions = (state, dispatch) => {
  function getUsers() {
    dispatch({ type: types.GET_USERS });
    axios
      .get("api address")
      .then(function(response) {
        dispatch({ type: types.GOT_USERS, payload: response.data });
      })
      .catch(function(error) {
        // handle error
      });
  }
  return {
    getUsers,
  };
};
  • Reducer(index.js):我使用了redux库中的CombineReducer函数代码
const AppReducer = combineReducers({
  client: clientReducer,
  user: userReducer,
});
  • Root.js
import React, { useContext, useReducer } from "react";
import AppContext from "./context";
import AppReducer from "./reducers";
import { clientActions } from "./actions/clientActions";
import { userActions } from "./actions/userActions";
import App from "./App";

const Root = () => {
  const initialState = useContext(AppContext);
  const [state, dispatch] = useReducer(AppReducer, initialState);
  const clientDispatch = clientActions(state, dispatch);
  const userDispatch = userActions(state, dispatch);

  return (
    <AppContext.Provider
      value={{
        clientState: state.client,
        userState: state.user,
        clientDispatch,
        userDispatch,
      }}
    >
      <App />
    </AppContext.Provider>
  );
};

export default Root;

因此,每当组件想要访问上下文存储或调度动作时,这就是我从组件执行的操作:

import React, { useContext } from "react";
import ListMenu from "../common/ListMenu";
import List from "./List";
import AppContext from "../../context";
import Frame from "../common/Frame";

const Example = props => {
  const { match, history } = props;
  const { userState, userDispatch } = useContext(AppContext);

  // Push to user detail route /user/userId
  const selectUserList = userId => {
    history.push(`/user/${userId}`);
    userDispatch.clearTabValue(true);
  };

  return (
    <Frame>
      <ListMenu
        dataList={userState.users}
        selectDataList={selectUserList}
      />
      <List />
    </Frame>
  );
};

export default Example;

我现在面临的问题是,每当我调度操作或尝试访问上下文存储时,由于上下文提供者包装了整个应用程序,所有组件都将重新呈现。

我想知道如何解决整个重新渲染问题(如果仍然可以使用我的action / reducer文件夹结构)。

此外,我正在从操作中获取数据,但我想将其与操作文件分开,就像我们在redux-saga结构上所做的一样。我想知道是否有人知道如何在不使用redux / redux-saga的情况下将其分开。

谢谢,如果您需要任何代码/文件来检查,请告诉我。

2 个答案:

答案 0 :(得分:0)

我曾经遇到过此重新渲染问题,并且在官方网站上找到了以下信息: https://reactjs.org/docs/context.html#caveats 也许它也会对您有帮助

答案 1 :(得分:0)

此效果(更新上下文更新中的组件)在official documentation中进行了描述。

  

当上下文值更改时,调用useContext的组件将始终重新呈现。如果重新渲染组件的成本很高,则可以使用备注对其进行优化

described

可能的解决方案

我认为通用解决方案是useMemo

例如

const Example = props => {
    const { match, history } = props;
    const { userState, userDispatch } = useContext(AppContext);

    // Push to user detail route /user/userId
    const selectUserList = userId => {
        history.push(`/user/${userId}`);
        userDispatch.clearTabValue(true);
    };
    const users = userState.users; 

    return useMemo(() => {
        return <Frame>
            <ListMenu
                dataList={users}
                selectDataList={selectUserList}
            />
            <List />
        </Frame>
    }, [users, selectUserList]);  // Here are variables that component depends on
};

我还建议您完全切换到Redux。您几乎可以使用combineReducersdispatch。 React-redux现在公开了useDispatch and useSelector hooks,因此您可以使您的代码非常接近您正在做的事情(用useContext替换useSelector,用{{1}替换useReducer }。这将需要对参数进行较小的更改)