【发布时间】:2021-06-17 07:00:33
【问题描述】:
在我的 react 应用程序中,我收到了这个奇怪的错误(“在渲染不同的组件 (yyy) 时无法更新组件 (xxx)”)。我理解是什么导致了错误,但我不理解“为什么”或如何在不重组大部分逻辑的情况下修复它。所以生命周期中的组件和底层逻辑如下: “App”是顶层组件,它包含一个名为“grid”的对象的状态。此状态及其设置器被传递给名为“Grid2”的组件。 Grid2 也有自己的状态,由 reducer 接口(React.useReducer 不是 React.useState)。这个 reducer 被传递了 App 状态(和状态内部的网格 obj)以及这个状态的设置器。所以reducer不仅返回Grid2状态的更新状态,还可以调用App状态的setter。 React 不喜欢这样,但我唯一直观的解决方案是将调用 App 的 setter 的所有逻辑移动到 useEffects 中,后者将监听 Grid2 状态的变化。
//--------------- App.tsx ---------------------
export const AppContext = React.createContext<AppContextType>({refs: initAppRefs, state: initAppState, setState: () => {}});
export function App() {
let { current: refs } = React.useRef<Refs>(initAppRefs);
const [state, setState] = React.useState<State>(initAppState);
return (
<AppContext.Provider value={{refs, state, setState}}>
<Home />
</AppContext.Provider>
);
}
//---------------- Grid2.tsx --------------------
import { AppContext, AppContextType, State } from "../App";
const gridStateReducer = (last: GridState, action: GridReducerAction): GridState => {
const newState: GridState = Helpers.deepCopy(last);
// centralized setter for tile.mouseDown, returns if change was made
const mouseDownOverride = (tile: string, value: boolean): boolean => {
// force tile to exist in newState.grid
if (!(tile in newState.grid)) {
newState.grid[tile] = {mouseDown: false, mouseOver: false};
}
// check to see if change is needed
if (newState.grid[tile].mouseDown !== value) {
newState.grid[tile].mouseDown = value;
// update appState grid fills
if (value) { //mousedown
if (tile in action.appState.grid) {
if (action.appState.currTool === "wall" && action.appState.grid[tile].fill === "empty") {
const newAppState: State = Helpers.deepCopy(action.appState);
newAppState.grid[tile].fill = "wall";
action.setAppState(newAppState);
}
}
}
return true;
} else {
return false;
}
}
if (action.type === GridReducerActionType.SetTileDown && action.data instanceof Array
&& typeof action.data[0] === "string" && typeof action.data[1] === "boolean") {
return mouseDownOverride(...(action.data as [string, boolean])) ? newState : last;
}
}
export const Grid2: React.FC<{}> = () => {
const { state: appState, setState: setAppState, refs: appRefs } = React.useContext<AppContextType>(AppContext);
const [gridState, gridStateDispatch] = React.useReducer(gridStateReducer, initGridState);
}
代码是来自实际项目的一组非常有选择性的逻辑,您可能会注意到很多引用似乎不知从何而来,但我省略了这段代码,因为它只会使代码膨胀并远离逻辑路径。所以我的问题是,为什么会发生这种情况(寻找引擎盖下的解释),以及如何在不进行过多重构的情况下解决这个问题?
【问题讨论】:
标签: reactjs typescript