将 React 上下文迁移到 Redux

问题描述 投票:0回答:1

我使用了一个免费的 React 模板,该模板是通过 Context+Reducer 实现的,很快,在增加复杂性后,我遇到了 useContext API 的经典重新渲染警告。是否可以将我的 Context 接口更改为 Redux 之一,因为我不想在每次调度单个操作时重新渲染所有内容。我目前正在使用 React v17.0.2


import { createContext, useContext, useReducer, useMemo } from "react";

// prop-types is a library for typechecking of props
import PropTypes from "prop-types";

//React main context
const MaterialUI = createContext();

// Setting custom name for the context which is visible on react dev tools
MaterialUI.displayName = "MaterialUIContext";

//React reducer
function reducer(state, action) {
  switch (action.type) {
    case "MINI_SIDENAV": {
      return { ...state, miniSidenav: action.value };
    }
    case "RESET_IDS": {
      return { ...state, chartIds: ["Main"] };
    }
    case "ADD_CHART": {
      return { ...state, chart: action.value, chartIds: [...state.chartIds, action.id] };
    }
    case "DELETE_CHART": {
      return {
        ...state,
        chart: action.value,
        chartIds: state.chartIds.filter((id) => id !== action.id),
      };
    }
    case "FILE_DATA": {
      return { ...state, fileData: action.value };
    }
    case "ANALYSIS_DATA": {
      return { ...state, analysisData: action.value };
    }
    case "DATA_UPLOADED": {
      return { ...state, isUploaded: action.value };
    }
    case "LAYOUT": {
      return { ...state, layout: action.value };
    }
    default: {
      throw new Error(`Unhandled action type: ${action.type}`);
    }
  }
}

// React context provider
function MaterialUIControllerProvider({ children }) {
  const initialState = {
    miniSidenav: false,
    chart: {},
    chartIds: ["Main"],
    fileData: [],
    analysisData: [],
    isUploaded: false,
    layout: "page",
    darkMode: false,
  };

  const [controller, dispatch] = useReducer(reducer, initialState);

  const value = useMemo(() => [controller, dispatch], [controller, dispatch]);

  return <MaterialUI.Provider value={value}>{children}</MaterialUI.Provider>;
}

//React custom hook for using context
function useMaterialUIController() {
  const context = useContext(MaterialUI);

  if (!context) {
    throw new Error(
      "useMaterialUIController should be used inside the MaterialUIControllerProvider."
    );
  }

  return context;
}

// Typechecking props for the MaterialUIControllerProvider
MaterialUIControllerProvider.propTypes = {
  children: PropTypes.node.isRequired,
};

// Context module functions
const setMiniSidenav = (dispatch, value) => dispatch({ type: "MINI_SIDENAV", value });
const resetIds = (dispatch) => dispatch({ type: "RESET_IDS" });
const addNewChart = (dispatch, value, id) => dispatch({ type: "ADD_CHART", value, id });
const deleteChart = (dispatch, value, id) => dispatch({ type: "DELETE_CHART", value, id });
const setFileData = (dispatch, value) => dispatch({ type: "FILE_DATA", value });
const setAnalysisData = (dispatch, value) => dispatch({ type: "ANALYSIS_DATA", value });
const setIsUploaded = (dispatch, value) => dispatch({ type: "DATA_UPLOADED", value });
const setLayout = (dispatch, value) => dispatch({ type: "LAYOUT", value });

export {
  MaterialUIControllerProvider,
  useMaterialUIController,
  setMiniSidenav,
  resetIds,
  addNewChart,
  deleteChart,
  setFileData,
  setAnalysisData,
  setIsUploaded,
  setLayout,
};

我试图更新 fileData 状态,但遇到了涉及无限重新渲染的重大问题,以及有关渲染速度和处理的一些非重大问题! 非常感谢任何帮助

javascript reactjs redux react-context
1个回答
0
投票

非常简单。安装完 redux 和 redux 工具包后。您可以像这样重构您的状态设置:

import { createSlice, configureStore } from '@reduxjs/toolkit';
import { Provider } from 'react-redux';

// define initial state
const initialState = {
  miniSidenav: false,
  chart: {},
  chartIds: ["Main"],
  fileData: [],
  analysisData: [],
  isUploaded: false,
  layout: "page",
  darkMode: false,
};

// define the slice
const materialSlice = createSlice({
  name: 'material',
  initialState,
  reducers: {
    setMiniSidenav: (state, action) => {
      state.miniSidenav = action.payload;
    },
    resetIds: (state) => {
      state.chartIds = ["Main"];
    },
    addNewChart: (state, action) => {
      state.chart = action.payload.value;
      state.chartIds = [...state.chartIds, action.payload.id];
    },
    deleteChart: (state, action) => {
      state.chart = action.payload.value;
      state.chartIds = state.chartIds.filter((id) => id !== action.payload.id);
    },
    setFileData: (state, action) => {
      state.fileData = action.payload;
    },
    setAnalysisData: (state, action) => {
      state.analysisData = action.payload;
    },
    setIsUploaded: (state, action) => {
      state.isUploaded = action.payload;
    },
    setLayout: (state, action) => {
      state.layout = action.payload;
    },
  },
});

export const {
  setMiniSidenav,
  resetIds,
  addNewChart,
  deleteChart,
  setFileData,
  setAnalysisData,
  setIsUploaded,
  setLayout,
} = materialSlice.actions;

// configure store
const store = configureStore({
  reducer: materialSlice.reducer,
});

// context provider
function MaterialUIControllerProvider({ children }) {
  return <Provider store={store}>{children}</Provider>;
}

export { MaterialUIControllerProvider };

然后您可以在组件中使用 useDispatch 和 useSelector 来选择状态并相应地更改它们。至于无限循环,您可能想检查您是否确实正在调度操作。也许它与你的 useEffect 中的依赖关系有关?

© www.soinside.com 2019 - 2024. All rights reserved.