使用 useReducer(React Hooks)从 API 设置初始状态时如何停止无限循环

How to stop infinite loop when setting initial state from API with useReducer (React Hooks)

我正在尝试通过 useReducer 设置我的初始状态。此数据来自 API,因此我将其放在 useEffect 中并应用了调度方法。 (我需要使用 useReducer 因为我稍后会有更复杂的逻辑。)这有效但是它会导致对 API 的无限次调用并且如果我控制台记录状态,它只会循环耗尽记忆。

供参考,当我使用 eg:

登录时
const { state, dispatch } = useContext(CanvasContext);
// console.log(state);

我只希望它在加载时变为 运行,但是当我将特定值添加到 useEffect 数组时它无济于事。有没有办法停止无限循环?我尝试使用检查是否已安装的方法(如其他答案所推荐的那样,但并不真正理解我应该用它做什么)。

谢谢。

export const CanvasContext = React.createContext([]);

function cartReducer(state, action) {
  switch (action.type) {
    case "INITIALIZE":
      return action.payload;
    default:
      return state;
  }
}

const initialState = {
  initialized: false,
  robots: [],
  cart: [],
};

export const CanvasProvider = ({ children }) => {
  const [state, dispatch] = useReducer(cartReducer, initialState);

  useEffect(() => {
    getStoredCanvas().then((response) => {
      dispatch({
        type: "INITIALIZE",
        payload: {
          ...initialState,
          robots: response?.data.elements,
          initialized: true,
        },
      });
    });
  }, []);

  return (
    <>
      {state.robots.length && (
        <CanvasContext.Provider value={{ state, dispatch }}>
          {children}
        </CanvasContext.Provider>
      )}
    </>
  );
};
// getStoredCanvas
export async function getStoredCanvas() {
  let canvas;
  try {
    if (useLocal) {
      canvas = axios.get(endPoints.local);
    } else {
      canvas = axios.post(endPoints.remote, testLoadCanvas);
      // .then((response) => console.log(response));
    }
    return canvas;
  } catch (error) {
    console.error(error);
  }
}

看起来你在乱扔一个 initialized 变量,但从未使用过它。似乎该变量仅在安装提供程序时才相关。话虽如此,我会将变量移动到状态变量中并使用它来确保初始化过程只发生一次:

export const CanvasProvider = ({ children }) => {
  const [state, dispatch] = useReducer(cartReducer, initialState);
  const [initialized, setInitialized] = useState(false)

  useEffect(() => {
    if(initialized) return 
    getStoredCanvas().then((response) => {
      setInitialized(true)
      dispatch({
        type: "INITIALIZE",
        payload: {
          ...initialState,
          robots: response?.data.elements,
        },
      });
    });
  }, [dispatch, initialized]);

  return (
    <>
      {state.robots.length && (
        <CanvasContext.Provider value={{ state, dispatch }}>
          {children}
        </CanvasContext.Provider>
      )}
    </>
  );
};