useState用法

useState

const [state, setState] = useState(initialState);

返回一个 state,以及更新 state 的函数。

在初始渲染期间,返回的状态 (state) 与传入的第一个参数 (initialState) 值相同。

setState 函数用于更新 state。它接收一个新的 state 值并将组件的一次重新渲染加入队列。

setState(newState);

在后续的重新渲染中,useState 返回的第一个值将始终是更新后最新的 state。

函数式更新

如果新的 state 需要通过使用先前的 state 计算得出,那么可以将函数传递给 setState该函数将接收先前的 state,并返回一个更新后的值。下面的计数器组件示例展示了 setState 的两种用法:

function Counter() {
  const [count, setCount] = useState(0);
  function handleClick() {
    setCount(count + 1)
  }
  function handleClickFn() {
    setCount((prevCount) => {
      return prevCount + 1
    })
  }
  return (
    <>
      Count: {count}
      <button onClick={handleClick}>+</button>
      <button onClick={handleClickFn}>+</button>
    </>
  );
}

两种方式的区别

注意上面的代码,handleClickhandleClickFn一个是通过一个新的 state 值更新,一个是通过函数式更新返回新的 state。现在这两种写法没有任何区别,但是如果是异步更新的话,那你就要注意了,他们是有区别的,来看下面例子:

function Counter() {
  const [count, setCount] = useState(0);
  function handleClick() {
    setTimeout(() => {
      setCount(count + 1)
    }, 3000);
  }
  function handleClickFn() {
    setTimeout(() => {
      setCount((prevCount) => {
        return prevCount + 1
      })
    }, 3000);
  }
  return (
    <>
      Count: {count}
      <button onClick={handleClick}>+</button>
      <button onClick={handleClickFn}>+</button>
    </>
  );
}

当我设置为异步更新,点击按钮延迟到3s之后去调用setCount函数,当我快速点击按钮时,也就是说在3s多次去触发更新,但是只有一次生效,因为 count 的值是没有变化的。

当使用函数式更新 state 的时候,这种问题就没有了,因为它可以获取之前的 state 值,也就是代码中的 prevCount 每次都是最新的值。

其实这个特点和类组件中 setState 类似,可以接收一个新的 state 值更新,也可以函数式更新。如果新的 state 需要通过使用先前的 state 计算得出,那么就要使用函数式更新。

因为setState更新可能是异步,当你在事件绑定中操作 state 的时候,setState更新就是异步的。

class Counter extends React.Component {
  constructor(props) {
    super(props)
    this.state = { count: 0 }
  }
  handleClick = () => {
    this.setState({ count: this.state.count + 1 })
    this.setState({ count: this.state.count + 1 })
    // 这样写只会加1
  }
  handleClickFn = () => {
    this.setState((prevState) => {
      return { count: prevState.count + 1 }
    })
    this.setState((prevState) => {
      return { count: prevState.count + 1 }
    })
  }
  render() {
    return (
      <>
        Count: {this.state.count}
        <button onClick={this.handleClick}>+</button>
        <button onClick={this.handleClickFn}>+</button>
      </>
    );
  }
}

当你在定时器中操作 state 的时候,而 setState 更新就是同步的。

class Counter extends React.Component {
  constructor(props) {
    super(props)
    this.state = { count: 0 }
  }
  handleClick = () => {
    setTimeout(() => {
      this.setState({ count: this.state.count + 1 })
      this.setState({ count: this.state.count + 1 })
      // 这样写是正常的,两次setState最后是加2
    }, 3000);
  }
  handleClickFn = () => {
    this.setState((prevState) => {
      return { count: prevState.count + 1 }
    })
    this.setState((prevState) => {
      return { count: prevState.count + 1 }
    })
  }
  render() {
    return (
      <>
        Count: {this.state.count}
        <button onClick={this.handleClick}>+</button>
        <button onClick={this.handleClickFn}>+</button>
      </>
    );
  }
}

注意这里的同步和异步指的是 setState 函数。因为涉及到 state 的状态合并,react 认为当你在事件绑定中操作 state 是非常频繁的,所以为了节约性能 react 会把多次 setState 进行合并为一次,最后在一次性的更新 state,而定时器里面操作 state 是不会把多次合并为一次更新的。

注意:与 class 组件中的 setState 方法不同,useState 不会自动合并更新对象。
转载自https://blog.csdn.net/wu_xianqiang/article/details/105181044,用以记录和自学,侵删。

posted @ 2021-12-21 12:00  柠檬派的奇幻漂流  阅读(818)  评论(0)    收藏  举报