reactjs - 避免由于其他组件使用的自定义钩子(Hook)而重新渲染组件?

标签 reactjs react-hooks redux-toolkit

我在不同的组件中使用这个自定义 http Hook 。

function useHttp(requestFunction, startWithPending = false) {  
  const httpState = useSelector((state) => state.http);
  const dispatch = useDispatch();
  
  const sendRequest = useCallback(

    async function (requestData) {

      dispatch(httpActions.loading(startWithPending));

      try {

        const responseData = await requestFunction(requestData);
        dispatch(httpActions.success(responseData));

      } catch (error) {

        dispatch(httpActions.error(error.message || "Something went wrong!!!"));
      }
    },
    [dispatch, requestFunction, startWithPending]
  );

  return {
    sendRequest,
    ...httpState,
  };
}

我正在使用 Redux 工具包(我的 http 操作)管理状态。

const initialHttpState = {
  status: null,
  data: null,
  error: null,
};

const httpSlice = createSlice({
  name: 'http',
  initialState: initialHttpState,
  reducers: {
    loading(state, action){
      state.status = action.payload ? 'pending' : 'null';
      state.data = null;
      state.error = null;
    },
    success(state, action){
      state.status = 'completed';
      state.data = action.payload;
      state.error = 'null'
    },
    error(state, action){
      state.status = 'error';
      state.data = null;
      state.error = action.payload;
    }
  }
})

我在多个组件的 useEffect 中使用这个钩子(Hook):

const { sendRequest, data, status, error } = useHttp(getProducts, true);

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

我的问题是,由于不同的组件使用相同的钩子(Hook),每当我尝试在组件内调用此自定义钩子(Hook)时,使用相同钩子(Hook)的任何其他组件都会重新渲染,这会导致我的应用程序崩溃(无法读取未定义错误的属性),因为如您所见,我将响应数据覆盖到同一位置,并且状态也在变化。
如何避免这个重新渲染问题?在我的组件内部,如何检查此重新渲染需求是来自其他组件还是组件本身?或者我如何改变我的状态管理结构来处理这个问题?

最佳答案

这是使用单个全局状态正是您想要从钩子(Hook)中得到的情况之一。每个 useHttp 钩子(Hook)都应该有自己的内部状态来管理请求并减轻处理任何响应值的责任。从 Redux 代码到使用 useReducer Hook 是一个相当简单的转换,因此每个 useHttp Hook 都有自己的状态和 reducer 逻辑。

示例:

const initialHttpState = {
  status: null,
  data: null,
  error: null,
};

const reducer = (state, action) => {
  switch(action.type) {
    case "loading":
      return {
        status: action.payload ? 'pending': null,
        data: null,
        error: null,
      };

    case "success":
      return {
        ...state,
        status: 'completed',
        data: action.payload,
        error: null,
      };

    case "error":
      return {
        ...state,
        status: 'error',
        data: null,
        error: action.payload,
      };

    default:
      return state;
  }
};

...

const useHttp = (requestFunction, startWithPending = false) => {
  const [httpState, dispatch] = React.useReducer(reducer, initialHttpState);

  const sendRequest = useCallback(
    async function (requestData) {
      dispatch(httpActions.loading(startWithPending));

      try {
        const responseData = await requestFunction(requestData);
        dispatch(httpActions.success(responseData));
      } catch (error) {
        dispatch(httpActions.error(error.message || "Something went wrong!!!"));
      }
    },
    [dispatch, requestFunction, startWithPending]
  );

  return {
    sendRequest,
    ...httpState,
  };
}

关于reactjs - 避免由于其他组件使用的自定义钩子(Hook)而重新渲染组件?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/71572239/

相关文章:

javascript - 使用类组件在 React Router v4 中嵌套路由

reactjs - 仅当输入中的所有元素发生变化时,如何使 useEffect Hook 调用提供的效果?

reactjs - React Context API 很慢

redux - 仅执行 'next-redux-wrapper' 时,真的需要在 'Next.js + Redux Toolkit' 应用程序中使用 'static generation' 吗?

javascript - 比较两个Object,判断不同属性的父节点

node.js - 查询 GraphQl 时的 GraphQl 和 Passport session : access req. 用户

reactjs - 在 rtk 查询中使用条件 header 的正确方法?

javascript - 从 Firebase 获取数据时,来自 Redux Toolkit 的 createAsyncThunk 会产生未定义的负载

javascript - React `onClick` 函数和类组件之间的更改

javascript - shouldComponentUpdate 等效于功能组件,以忽略状态更改