【问题标题】:How to update state when using React Context?使用 React Context 时如何更新状态?
【发布时间】:2020-02-10 07:47:35
【问题描述】:

我正在使用 React Context 像这样传入 state 和 setState

const [authContext, setAuthData] = useState({
    isAuthenticated: false,
    userID:"-1",
    email:"test",
    name:"test"
  });

<AuthContext.Provider value={[authContext,setAuthData]}>
          <Router>
            <NavbarMenu />
              <div className="AllElements">
                  <Switch>
                    <Route exact path="/" component={HomePage} />
                    <Route component={Routes} />
                  </Switch>
              </div>
          </Router>
        </AuthContext.Provider> 

在另一个组件中,我像这样检索它

const [authContext, setAuthData ] = useContext(AuthContext);
const { isAuthenticated } = authContext;

每当我想更新 authContext 时,我都会像这样调用 setAuthData

const HomePage = () => {
if(data && data.login && data.login.token){
        console.log("Data token exists");
        setAuthData(() => [{
            isAuthenticated: true,
            userID:data.login.id,
            email:data.login.email,
            name:data.login.name
        }]);
    } 

 return (<div><p>test</p></div>);
};
export default HomePage;

但是,一旦它命中 setAuthData,if {} 中的所有内容都会被多次调用。我一直在控制台中看到多个“数据令牌存在”,直到它错误超出最大更新深度

【问题讨论】:

  • 为什么不传递一个函数(更新父组件本身的状态)而不是直接传递 setState?
  • 为什么要在主页 comp 中返回 setAuthData 内的数组?
  • 因为我还需要在其他组件中重用 AuthContext。我不想将相同的函数作为道具传递给我想要重用的每个组件。

标签: reactjs react-context


【解决方案1】:

你会得到一个无限循环,因为 setAuthData 调用改变了 authContext。当 authContext 发生变化时 HomePage 会重新渲染并再次触发 setAuthData。

确保你只调用一次 setAuthData 例如:

const HomePage = () => {
  React.useEffect(() => {
    if (data && data.login && data.login.token) {
      console.log("Data token exists");
      setAuthData(() => [
        {
          isAuthenticated: true,
          userID: data.login.id,
          email: data.login.email,
          name: data.login.name
        }
      ]);
    }
  }, [data]);

 return (<div><p>test</p></div>);
};

【讨论】:

    【解决方案2】:

    我猜你应该在useEffect钩子中进行状态更新,并传递第二个参数以仅在更新时做出反应:

    const HomePage = () => {
    
        useEffect(()=>{
            //if(data && data.login && data.login.token){
                console.log("Data token exists");
                setAuthData(() => [{
                    isAuthenticated: true,
                    userID:data.login.id,
                    email:data.login.email,
                    name:data.login.name
                }]);
           // } 
         }, [data]); //<-----second param if it has any changes then run effect
         return (<div><p>test</p></div>);
    
    };
    

    【讨论】:

      【解决方案3】:

      这可能是问题:

      const HomePage = () => {
      if(data && data.login && data.login.token){
              console.log("Data token exists");
              setAuthData(() => [{
                  isAuthenticated: true,
                  userID:data.login.id,
                  email:data.login.email,
                  name:data.login.name
              }]);
          } 
      
       return (<div><p>test</p></div>);
      };
      export default HomePage;
      

      您更新的状态应该是一个对象,而不是基于父组件中先前状态的数组,因此将返回值更改为:

      const HomePage = () => {
      if(data && data.login && data.login.token){
              console.log("Data token exists");
              setAuthData(() => ({
                  isAuthenticated: true,
                  userID:data.login.id,
                  email:data.login.email,
                  name:data.login.name
              }));
          } 
      
       return (<div><p>test</p></div>);
      };
      export default HomePage;
      

      正如彼得的回答中所述,您还应该使用 useEffect 挂钩来停止更新周期。

      【讨论】:

        猜你喜欢
        • 2020-07-18
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-12-31
        • 2021-09-09
        • 1970-01-01
        • 2020-07-26
        • 1970-01-01
        相关资源
        最近更新 更多