我使用了一个免费的 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 状态,但遇到了涉及无限重新渲染的重大问题,以及有关渲染速度和处理的一些非重大问题! 非常感谢任何帮助
非常简单。安装完 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 中的依赖关系有关?