繁体   English   中英

为什么更新反应上下文值时我的 useEffect() 不会触发?

[英]Why won't my useEffect() hook fire when updating a react context value?

为什么更新使用 React 上下文的依赖项时我的useEffect挂钩不会触发? 我将上下文用作向导的一部分,该向导将从用户那里收集大量数据,然后最终在向导的最后一步进行处理。

Person字段正在更新,在向导的下一页上,我可以检索它们(为简洁起见,我的示例中未显示)。 但是,我想在用户输入姓名和地址后在useEffect中进行 API 调用以执行一些处理。

这是代码(有点做作):

export interface Person {
  name: string;
  address: string;
  skills: string[]; // collected on a different wizard page
};

const PersonContext = React.createContext(null);

const PersonProvider: React.FC = ({children}) => {
  const [personState, setPersonState] = useState<Person>({
    name: "",
    address: ""
  });

  return ( 
    <PersonContext.Provider value={personState}>
      {children}
    </PersonContext.Provider>
  );
};

export const PersonPage: React.FC<{}> = () => {
  const personState = useContext(PersonContext);
  
  useEffect(() => {
    console.log("useEffect");
  }, [personState]);
  
  /*
  Also tried, but no joy:

  useEffect(() => {
    console.log("useEffect");
  }, [personState.name, personState.address]);
  */

  const onNameChanged = (e) => {
    if(event.key === "Enter") {
      console.log(`name: ${e.target.value}`);
      personState.name = e.target.value;
    }
  };
  
  const onAddressChanged = (e) => {
    if(event.key === "Enter") {
      console.log(`name: ${e.target.value}`);
      personState.address = e.target.value;
    }
  };
  
  return (
    <div>
      Name: <input name="name" onKeyDown={(e) => onNameChanged(e)} /> (press enter)
      <br />
      You typed: <span>{personState.name}</span>
      <br/>
      <br/>
      Address: <input name="address" onKeyDown={(e) => onAddressChanged(e)} /> (press enter)
      <br />
      You typed: <span>{personState.address}</span>
    </div>
  );
};

export const App: React.FC<{}> = () => {
  return (
    <PersonProvider>
      <PersonPage />
    </PersonProvider>
  );
}

我这里还有一个 CodePen 示例:

https://codepen.io/kevstercode/pen/gOexPea

您正在改变 object。 您应该使用 setState function 来更新它,例如。

代替

const onAddressChanged = (e) => {
 if(event.key === "Enter") {
  personState.address = e.target.value;
 }
};

做这个

const onAddressChanged = (e) => {
 if(event.key === "Enter") {
  setPersonState(prevState => {...prevState, address: e.target.value)}
 }
};
const PersonProvider: React.FC = ({children}) => {
  // you should expose both the state object and its setter
  const personGetterSetter = useState<Person>({
    name: "",
    address: ""
  });

  return ( 
    <PersonContext.Provider value={personGetterSetter}>
      {children}
    </PersonContext.Provider>
  );
};
export const PersonPage: React.FC<{}> = () => {
  // unpack them here
  const [personState, setPersonState] = useContext(PersonContext);
  
  useEffect(() => {
    console.log("useEffect");
  }, [personState]);

  const onNameChanged = (e) => {
    if(event.key === "Enter") {
      console.log(`name: ${e.target.value}`);

      // Wrong way to go
      // do not mutate state object directly

      // personState.name = e.target.value;

      // use the setter, this is the react way to update state
      setPersonState(personState => {
        return { ...personState, name: e.target.value }
      })
    }
  };
  
   ...
};

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM