You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React中useContext+useEffect持久化localStorage数据失败问题

React中useContext结合useEffect持久化数据遇条件渲染失效问题

我在React中用useContext配合useEffect,想把useContext里的数据持久化到localStorage,但因为条件渲染导致功能失效。需求很明确:用户未登录时显示登录按钮,登录后切换成登出按钮。

目前已经实现了点击弹窗内的登录按钮,把user的初始null状态改成“User is logged in”。但遇到了问题:
在SignInDialog.js里我写了一个依赖弹窗open属性的useEffect,原本预期弹窗打开或关闭时都会打印“useEffect setItem 2”,但实际只有打开弹窗后点击侧边关闭时这个useEffect能正常触发;点击登录按钮关闭弹窗后,这个useEffect完全没触发。

排查后发现,user的值被用于父组件Main.js的条件渲染,只要把这个条件渲染去掉,所有功能就恢复正常了。我怀疑是父子组件的渲染顺序导致的问题,但暂时找不到不改动现有实现方案的修复方法。


相关代码

UserContext.js

import { createContext } from "react";

export const UserContext = createContext(null);

App.js

export default function App() {
  const [user, setUser] = useState();

  return (
    <div className="App">
      <UserContext.Provider value={{ user, setUser }}>
        <Main />
      </UserContext.Provider>
    </div>
  );
}

Main.js

export default function Main() {
  const { user, setUser } = useContext(UserContext);

  const logOut = () => {
    setUser(null);
  };

  return (
    <div className="App">
      {/* 只保留SignInButton不加条件渲染的话功能正常  */}
      {/* <div>
          <SignInButton />
      </div> */}

      {user ? (
        <div>
          <Typography>{user}</Typography>
          <Button onClick={logOut}>Log out</Button>
        </div>
      ) : (
        <div>
          <SignInButton />
        </div>
      )}
    </div>
  );
}

SignInButton.js

const SignInButton = () => {
  const [openSignInDialog, setOpenSignInDialog] = useState(false);

  const handleSignInClickOpen = () => {
    setOpenSignInDialog(true);
  };

  return (
    <StyledEngineProvider injectFirst={true}>
      <div>
        <Button onClick={handleSignInClickOpen}> Sign in </Button>
        <SignInDialog open={openSignInDialog} setOpen={setOpenSignInDialog} />
      </div>
    </StyledEngineProvider>
  );
};
export default SignInButton;

SignInDialog.js

export default function SignInDialog(props) {
  const { user, setUser } = useContext(UserContext);

  useEffect(() => {
    console.log(">>>>>>>>useEffect getItem 1");
    /* const data = window.localStorage.getItem('uli')
    console.log(`data = ${data}`) */
  }, []);

  useEffect(() => {
    console.log(">>>>>>>>useEffect setItem 2");
    /* window.localStorage.setItem('uli', user) */
  }, [props.open]);
  {
    /* 最终目标是把user作为依赖,现在先这样留着测试 */
  }

  const test = () => {
    setUser("User logged in");
    props.setOpen(false);
    {
      /* 注释掉props.setOpen(false)也没区别 */
    }
  };

  const handleClose = () => {
    props.setOpen(false);
  };

  return (
    <div className="App">
      <Dialog open={props.open} onClose={handleClose}>
        <Box component="form">
          <DialogTitle>Sign in data</DialogTitle>
          <DialogContent>
            <DialogContentText>username, password..</DialogContentText>
          </DialogContent>
          <DialogActions>
            <Button type="button" onClick={test}>
              Sign in
            </Button>
          </DialogActions>
        </Box>
      </Dialog>
    </div>
  );
}

内容的提问来源于stack exchange,提问作者hanku8

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.10 23:10:12