首页 > 解决方案 > 反应子状态没有得到更新

问题描述

我有一个使用钩子初始化状态的父组件。我将钩子的状态和 setState 传递给子节点,但是每当我更新多个子节点的状态时,它们都会更新不是最新状态的状态。

重现问题:当您创建链接并在您的信息中写入并单击提交时,它成功附加到父状态。如果在此之后添加另一个,它也会成功附加到父状态。但是当您返回并在第一个链接上按提交时,它会出于某种原因破坏第二个链接。请在我的代码沙盒上尝试一下。

基本上我想要的是一个制作新表单的按钮。在每个表单中,您都可以选择社交媒体类型,如 fb、instagram、tiktok,还可以输入文本字段。这些数据存储在状态中,最后当您单击应用更改时,我希望它存储在我的数据库中,即 firestore。你能帮我解决这个问题吗?这是一个代码沙箱。

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

这是我的代码:

管理员.js

import React, { useState } from 'react';
import Button from '@material-ui/core/Button';
import AddNewLink from './AddNewLink';

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);
    // firebase.addLinksToUser(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;

AddNewLink.js


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;

标签: javascriptreactjsreact-hooks

解决方案


我所看到的是 AddNewLink 中的链接将是一个过时的关闭,但在你的问题中你从不使用它。这是你的代码“工作”,因为你没有描述它应该做什么它总是“工作”

const { useState } = React;

const AddNewLink = (props) => {
  const [socialMedia, setSocialMedia] = useState('');
  const [url, setUrl] = useState('');
  const { updateLinks, links } = props.linkData;
  console.log('links is a stale closure:', links);

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

  return (
    <div>
      <select
        value={socialMedia}
        onChange={(e) => {
          setSocialMedia(e.target.value);
        }}
      >
        <option value="">select item</option>
        <option value={'facebook'}>Facebook</option>
        <option value={'instagram'}>Instagram</option>
        <option value={'tiktok'}>TikTok</option>
      </select>
      <input
        type="text"
        id="standard-basic"
        label="Enter link"
        style={{ width: '95%' }}
        onChange={(e) => {
          setUrl(e.target.value);
        }}
      />
      <button
        type="submit"
        variant="contained"
        color="primary"
        style={{ marginBottom: '30px' }}
        onClick={() => handleSubmit()}
      >
        Submit
      </button>
    </div>
  );
};

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);
    // firebase.addLinksToUser(links);
  };

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

ReactDOM.render(<Admin />, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
<div id="root"></div>

将 jsx 置于本地状态并不是一个好主意,而是将数据保存在状态中,并在每次渲染时将其传递给组件。


推荐阅读