React子状态未更新

时间:2020-07-23 19:47:08

标签: javascript reactjs react-hooks

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

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

基本上我想要的是创建新表格的按钮。在每种形式中,您都可以选择社交媒体类型,例如fb,instagram,tiktok,还可以输入文本字段。这些数据以状态存储,最后单击“应用更改”时,我希望将其存储在Firestore数据库中。你能帮我解决这个问题吗?这是上面的代码沙箱。

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

这是我的代码:

Admin.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;

1 个答案:

答案 0 :(得分:1)

我所看到的是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置于本地状态,而是将数据保存为状态,然后在每次渲染时将其传递给组件不是一个好主意。