繁体   English   中英

反应如何修复子组件中过时的 state

[英]React how to fix stale state in child component

创建多个子组件,每个子组件都可以设置其父组件的状态,使这些子组件具有不同版本的 state 历史(又名陈旧状态)

要重现错误:

  1. 通过单击“添加新社交媒体”创建 2 个子组件
  2. 提交两个子组件以设置父 state
  3. 再次提交第一个创建的组件,现在第二个组件输入从生成的 state 中消失

另一个错误:

  1. 通过单击“添加新社交媒体”创建 2 个子组件
  2. 提交第二个创建的子组件
  3. 提交第一个创建的子组件,现在第二个组件输入从生成的 state 中消失

总而言之,我希望生成的 state 拥有每个组件的所有数据。 我怎样才能解决这个问题?

https://codesandbox.io/s/blissful-fog-oz10p

const Admin = () => {
  const [links, setLinks] = useState({});
  const [newLink, setNewLink] = useState([]);

  const updateLinks = (socialMedia, url) => {
    setLinks({
      ...links,
      [socialMedia]: url
    });
  };

  const linkData = {
    links,
    updateLinks
  };

  const applyChanges = () => {
    console.log(links);
  };

  return (
    <>
      {newLink ? newLink.map(child => child) : null}
      <div className="container-sm">
        <Button
          type="submit"
          fullWidth
          variant="contained"
          color="primary"
          onClick={() => {
            setNewLink([
              ...newLink,
              <AddNewLink key={Math.random()} linkData={linkData} />
            ]);
          }}
        >
          Add new social media
        </Button>
        <Button
          type="submit"
          fullWidth
          variant="contained"
          color="primary"
          style={{ marginTop: "50px" }}
          onClick={() => applyChanges()}
        >
          Apply Changes
        </Button>
        <h3>{JSON.stringify(links, null, 4)}</h3>
      </div>
    </>
  );
};

export default Admin;

const AddNewLink = props => {
  const [socialMedia, setSocialMedia] = useState("");
  const [url, setUrl] = useState("");
  const { updateLinks } = props.linkData;

  const handleSubmit = () => {
    updateLinks(socialMedia, url);
  };

  return (
    <>
      <FormControl
        style={{ marginTop: "30px", marginLeft: "35px", width: "90%" }}
      >
        <InputLabel>Select Social Media</InputLabel>
        <Select
          value={socialMedia}
          onChange={e => {
            setSocialMedia(e.target.value);
          }}
        >
          <MenuItem value={"facebook"}>Facebook</MenuItem>
          <MenuItem value={"instagram"}>Instagram</MenuItem>
          <MenuItem value={"tiktok"}>TikTok</MenuItem>
        </Select>
      </FormControl>
      <form
        noValidate
        autoComplete="off"
        style={{ marginBottom: "30px", marginLeft: "35px" }}
      >
        <TextField
          id="standard-basic"
          label="Enter link"
          style={{ width: "95%" }}
          onChange={e => {
            setUrl(e.target.value);
          }}
        />
      </form>
      <div className="container-sm">
        <Button
          type="submit"
          fullWidth
          variant="contained"
          color="primary"
          style={{ marginBottom: "30px" }}
          onClick={() => handleSubmit()}
        >
          Submit
        </Button>
      </div>
    </>
  );
};

export default AddNewLink;

您面临的问题是由updateLinks() function关闭links state 引起的。

当您创建两个AddNewLink组件时,每个组件都会传递updateLinks() function。 由于最初, links是一个空的 object, updateLinks() function 传递给AddNewLink的两个实例,对links变量有一个闭包,当时的links是指一个空的 ZA8CFDE6331BD59EB2AC96F8911C4B6 {} 6。 因此,当您提交表单时,就updateLinks() function 而言, links是一个空的 object。 因此,当将links与从AddNewLink组件传递的数据合并时,只有来自提交表单的数据会保存在 state 中,因为links是一个空的 object。

解决方案:

您可以使用useRef挂钩访问updateLinks() function 中links的最新值。

const Admin = () => {
   ...
   
   const linkRef = useRef();

   const updateLinks = (socialMedia, url) => {
      linkRef.current = { ...linkRef.current, [socialMedia]: url };
      setLinks(linkRef.current);
   };
   
   ...
};

此外,我认为您不需要多个AddNewLink组件实例。 您可以在 state 中添加多个社交媒体链接,只需一个AddNewLink组件实例。

演示:

编辑 sharp-tdd-hym00

暂无
暂无

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

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