setState 不会立即更新状态

IT技术 javascript reactjs ecmascript-6
2021-02-03 20:24:46

我想问一下为什么我在做onClick活动时我的状态没有改变我前段时间搜索过我需要onClick在构造函数中绑定函数,但状态仍然没有更新。

这是我的代码:

import React from 'react';
import Grid from 'react-bootstrap/lib/Grid';
import Row from 'react-bootstrap/lib/Row';
import Col from 'react-bootstrap/lib/Col';
import BoardAddModal from 'components/board/BoardAddModal.jsx';    
import style from 'styles/boarditem.css';

class BoardAdd extends React.Component {
    constructor(props) {
        super(props);    
        this.state = {
            boardAddModalShow: false
        };    
        this.openAddBoardModal = this.openAddBoardModal.bind(this);
    }

    openAddBoardModal() {
        this.setState({ boardAddModalShow: true }); // set boardAddModalShow to true

        /* After setting a new state it still returns a false value */
        console.log(this.state.boardAddModalShow);   
    }

    render() {    
        return (
            <Col lg={3}>
                <a href="javascript:;" 
                   className={style.boardItemAdd} 
                   onClick={this.openAddBoardModal}>
                    <div className={[style.boardItemContainer,
                                     style.boardItemGray].join(' ')}>
                        Create New Board
                    </div>
                </a>
            </Col>
        );
    }
}

export default BoardAdd
6个回答

您的状态需要一些时间来改变,并且由于console.log(this.state.boardAddModalShow)在状态改变之前执行,您将获得先前的值作为输出。所以需要在回调setState函数中写console

openAddBoardModal() {
  this.setState({ boardAddModalShow: true }, function () {
    console.log(this.state.boardAddModalShow);
  });
}

setState是异步的。这意味着您不能在一行调用它并假设状态在下一行发生了变化。

根据React 文档

setState()不会立即变异,this.state而是创建一个挂起的状态转换。this.state调用此方法后访问可能会返回现有值。无法保证对 setState 调用的同步操作,并且可能会批量调用以提高性能。

他们为什么要setState异步

这是因为setState改变了状态并导致重新渲染。这可能是一项昂贵的操作,并且使其同步可能会使浏览器无响应。

因此,setState调用是异步的并且是批处理的,以获得更好的 UI 体验和性能。

@maudev,eslint 规则阻止你使用 console.logs,这样它们就不会在生产中结束,但上面的例子纯粹是为了调试。和 console.log 并替换为考虑更新状态的操作
2021-03-09 20:24:46
@ShubhamKhatri 谢谢,我昨天解决了。我使用了相同的 useEffect 钩子。
2021-03-11 20:24:46
@VaibhavSidapara 检查这篇文章。让我知道它是否有帮助
2021-03-28 20:24:46
到目前为止,这是一个好主意,但是如果我们因为使用 eslint 规则而不能使用 console.log 怎么办?
2021-04-02 20:24:46
如果回调不像你说的那样工作怎么办?我的没有!
2021-04-04 20:24:46

幸运的是 setState()需要回调。这是我们获得更新状态的地方。

考虑这个例子。

this.setState({ name: "myname" }, () => {                              
        //callback
        console.log(this.state.name) // myname
      });

所以当回调触发时, this.state 是更新的状态。
您可以mutated/updated在回调中获取数据。

您还可以使用此回调来传递任何函数,initMap()例如
2021-03-09 20:24:46
这在 ReactJS 功能组件中发出警告
2021-03-17 20:24:46
加油!终于解决了我的问题。非常感谢。
2021-04-08 20:24:46

由于 setSatate 是一个异步函数,因此您需要像这样将状态作为回调进行控制台。

openAddBoardModal(){
    this.setState({ boardAddModalShow: true }, () => {
        console.log(this.state.boardAddModalShow)
    });
}

对于尝试使用钩子执行此操作的任何人,您都需要useEffect.

function App() {
  const [x, setX] = useState(5)
  const [y, setY] = useState(15) 

  console.log("Element is rendered:", x, y)

  // setting y does not trigger the effect
  // the second argument is an array of dependencies
  useEffect(() => console.log("re-render because x changed:", x), [x])

  function handleXClick() {
    console.log("x before setting:", x)
    setX(10)
    console.log("x in *line* after setting:", x)
  }

  return <>
    <div> x is {x}. </div>
    <button onClick={handleXClick}> set x to 10</button>
    <div> y is {y}. </div>
    <button onClick={() => setY(20)}> set y to 20</button>
  </>
}

输出:

Element is rendered: 5 15
re-render because x changed: 5
(press x button)
x before setting: 5
x in *line* after setting: 5
Element is rendered: 10 15
re-render because x changed: 10
(press y button)
Element is rendered: 10 20

setState()并不总是立即更新组件。它可能会批量更新或推迟更新。这使得在调用setState()潜在陷阱后立即阅读 this.state 相反,使用componentDidUpdatesetState回调 ( setState(updater, callback)),这两者都保证在应用更新后触发。如果您需要根据之前的状态设置状态,请阅读下面的更新程序参数。

setState()除非shouldComponentUpdate()返回 false,否则将始终导致重新渲染如果正在使用可变对象并且无法在 中实现条件渲染逻辑shouldComponentUpdate(),则setState()仅在新状态与先前状态不同时调用将避免不必要的重新渲染。

第一个参数是带有签名的更新程序函数:

(state, props) => stateChange

state是对应用更改时组件状态的引用。它不应该被直接变异。相反,应该通过基于 state 和 props 的输入构建一个新对象来表示更改。例如,假设我们想通过 props.step 增加 state 中的一个值:

this.setState((state, props) => {
    return {counter: state.counter + props.step};
});