在React中,useState()是什么?

230

我目前正在学习React中的钩子概念,并尝试理解以下示例。

import { useState } from 'react';

function Example() {
    // Declare a new state variable, which we'll call "count"
    const [count, setCount] = useState(0);

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>
        Click me
      </button>
    </div>
  );
}

以上示例在处理函数参数本身上递增计数器。如果我想要在事件处理程序函数内修改计数值怎么办?

请考虑下面的示例:

setCount = () => {
  //how can I modify count value here. Not sure if I can use setState to modify its value
  //also I want to modify other state values as well here. How can I do that
}

<button onClick={() => setCount()}>
  Click me
</button>

您还可以查看源代码以了解useState的实现方式。这是16.9版本的定义 - chemturion
14个回答

245

React hooks是一种新的(仍在开发中)访问React的核心功能,如state而无需使用类的方法。例如,在处理程序函数中直接递增计数器而不直接在onClick属性中指定它,您可以执行以下操作:

...
const [count, setCounter] = useState(0);
const [moreStuff, setMoreStuff] = useState(...);
...

const setCount = () => {
    setCounter(count + 1);
    setMoreStuff(...);
    ...
};

并且 onClick:

<button onClick={setCount}>
    Click me
</button>

让我们快速解释一下这行代码的含义:

const [count, setCounter] = useState(0);

useState(0)返回一个元组,其中第一个参数count是计数器的当前状态,而setCounter是允许我们更新计数器状态的方法。我们可以在任何地方使用setCounter方法来更新count的状态-在这种情况下,我们正在setCount函数内部使用它,我们可以做更多的事情;钩子的理念是,如果不需要,则能够使我们的代码更加功能化并避免基于类的组件。

我写了一篇完整的关于钩子的文章,包括多个例子(包括计数器),例如这个codepen,我使用了useStateuseEffectuseContext和自定义钩子custom hooks。我可以详细介绍钩子如何工作,但文档已经很好地解释了状态钩子和其他钩子的详细信息。

更新:16.8版本以来,钩子不再是建议性的,它们现在可以使用,在React的网站上有一个部分回答了一些常见问题


11
很好的比喻,不过严格来说JavaScript没有元组数据类型。 - goonerify
嗯,解构赋值就像元组一样使用。 - Naveen DA
钩子是异步的吗?当使用 setSomething 时,如果我紧接着尝试直接使用 something,它似乎仍然具有旧值... - Byron Coetsee
1
Hooks在“set value”调用后不会立即更新其值,直到组件重新渲染。通过Hookstate(https://hookstate.js.org/)库的超级强化useState,您可以获得即时值更新和更多功能。免责声明:我是该库的作者。 - Andrew
你能否解释一下为什么我们将 const 与一个明显会改变的状态相关联?const count 看起来很奇怪。 - Adelin
@goonerify 元组是一个有限的有序元素列表(序列)。 - default_avatar

78

useState是React中的一个内置Hook,从0.16.7版本开始提供。

useState只应该在函数组件中使用。如果我们需要一个内部状态,并且不需要实现更复杂的逻辑,比如生命周期方法,那么useState就是解决方案。

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

返回一个状态值及其更新函数。在初始渲染期间,返回的状态 (state) 与作为第一个参数 (initialState) 传递的值相同。使用 setState 函数来更新状态。它接受一个新状态值并排队重新渲染组件。请注意,useState 钩子用于更新状态的回调函数的行为与组件的 this.setState 不同。为了展示区别,我准备了两个示例。

class UserInfoClass extends React.Component {
  state = { firstName: 'John', lastName: 'Doe' };
  
  render() {
    return <div>
      <p>userInfo: {JSON.stringify(this.state)}</p>
      <button onClick={() => this.setState({ 
        firstName: 'Jason'
      })}>Update name to Jason</button>
    </div>;
  }
}

// Please note that new object is created when setUserInfo callback is used
function UserInfoFunction() {
  const [userInfo, setUserInfo] = React.useState({ 
    firstName: 'John', lastName: 'Doe',
  });

  return (
    <div>
      <p>userInfo: {JSON.stringify(userInfo)}</p>
      <button onClick={() => setUserInfo({ firstName: 'Jason' })}>Update name to Jason</button>
    </div>
  );
}

ReactDOM.render(
  <div>
    <UserInfoClass />
    <UserInfoFunction />
  </div>
, document.querySelector('#app'));
<script src="https://unpkg.com/react@16.7.0-alpha.0/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@16.7.0-alpha.0/umd/react-dom.development.js"></script>

<div id="app"></div>

当使用 setUserInfo 回调函数时,会创建一个新的对象。请注意,我们丢失了 lastName 键的值。为了修复这个问题,我们可以将函数传递到 useState 中。

setUserInfo(prevState => ({ ...prevState, firstName: 'Jason' })

查看示例:

// Please note that new object is created when setUserInfo callback is used
function UserInfoFunction() {
  const [userInfo, setUserInfo] = React.useState({ 
    firstName: 'John', lastName: 'Doe',
  });

  return (
    <div>
      <p>userInfo: {JSON.stringify(userInfo)}</p>
      <button onClick={() => setUserInfo(prevState => ({
        ...prevState, firstName: 'Jason' }))}>
        Update name to Jason
      </button>
    </div>
  );
}

ReactDOM.render(
    <UserInfoFunction />
, document.querySelector('#app'));
<script src="https://unpkg.com/react@16.7.0-alpha.0/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@16.7.0-alpha.0/umd/react-dom.development.js"></script>

<div id="app"></div>

Unlike the setState method found in class components, useState does not automatically merge update objects. You can replicate this behavior by combining the function updater form with object spread syntax:

setState(prevState => {
  // Object.assign would also work
  return {...prevState, ...updatedValues};
});

要了解更多关于useState的内容,请参阅官方文档


2
感谢您在示例中添加了一个函数作为参数。 - Juni Brosas
1
你的比较示例帮助像我这样的新手理解了useState的使用。 - SimpleGuy

25
useState钩子的语法很简单。const [value, setValue] = useState(defaultValue)。如果您对这种语法不熟悉,请点击此处。我建议您阅读文档,其中有出色的解释和相当数量的示例。

import { useState } from 'react';

function Example() {
    // Declare a new state variable, which we'll call "count"
    const [count, setCount] = useState(0);
  
  // its up to you how you do it
  const buttonClickHandler = e => {
   // increment
   // setCount(count + 1)
   
   // decrement
   // setCount(count -1)
   
   // anything
   // setCount(0)
  }
  

  return (
       <div>
          <p>You clicked {count} times</p>
         <button onClick={buttonClickHandler}>
             Click me
         </button>
      </div>
   );
 }


这应该是被接受的答案。简洁明了,附有良好的外部参考资料。 - varun
这是最差的答案,基本上只是复制/粘贴文档页面。我来到这里是因为文档页面令人困惑。 - reggaeguitar
朋友,你有什么困惑吗?很难找到比官方文档更好的解释了。 - Jan Ciołek

12

useState() 是 React 的一个 Hook。Hooks 让函数组件能够使用状态和可变性。

虽然你不能在类中使用 hooks,但是你可以将类组件包装在一个函数组件中,并从函数组件中使用 hooks。这是将组件从类形式迁移到函数形式的好工具。下面是一个完整的例子:

在此示例中,我将使用计数器组件。它是这样的:

class Hello extends React.Component {
  constructor(props) {
    super(props);
    this.state = { count: props.count };
  }
  
  inc() {
    this.setState(prev => ({count: prev.count+1}));
  }
  
  render() {
    return <button onClick={() => this.inc()}>{this.state.count}</button>
  }
}

ReactDOM.render(<Hello count={0}/>, document.getElementById('root'))
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id='root'></div>

这是一个简单的类组件,其中包含一个计数状态,通过方法更新状态。这是类组件中非常常见的模式。首先要将其包装在一个名字完全相同的函数组件中,该函数组件将其所有属性委托给包装的组件。此外,您需要在函数返回中呈现包装的组件。代码如下:

function Hello(props) {
  class Hello extends React.Component {
    constructor(props) {
      super(props);
      this.state = { count: props.count };
    }

    inc() {
      this.setState(prev => ({count: prev.count+1}));
    }

    render() {
      return <button onClick={() => this.inc()}>{this.state.count}</button>
    }
  }
  return <Hello {...props}/>
}

ReactDOM.render(<Hello count={0}/>, document.getElementById('root'))
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id='root'></div>

这是完全相同的组件,具有相同的行为、名称和属性。现在让我们将计数状态提升到函数组件中。步骤如下:

function Hello(props) {
  const [count, setCount] = React.useState(0);
  class Hello extends React.Component {
    constructor(props) {
      super(props);
      this.state = { count: props.count };
    }

    inc() {
      this.setState(prev => ({count: prev.count+1}));
    }

    render() {
      return <button onClick={() => setCount(count+1)}>{count}</button>
    }
  }
  return <Hello {...props}/>
}

ReactDOM.render(<Hello count={0}/>, document.getElementById('root'))
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.6/umd/react.production.min.js" integrity="sha256-3vo65ZXn5pfsCfGM5H55X+SmwJHBlyNHPwRmWAPgJnM=" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.6/umd/react-dom.production.min.js" integrity="sha256-qVsF1ftL3vUq8RFOLwPnKimXOLo72xguDliIxeffHRc=" crossorigin="anonymous"></script>
<div id='root'></div>

请注意,方法inc仍然存在,它不会对任何人造成伤害,实际上是死代码。这就是概念,只需继续提升状态。一旦完成,您可以删除类组件:

function Hello(props) {
  const [count, setCount] = React.useState(0);

  return <button onClick={() => setCount(count+1)}>{count}</button>;
}

ReactDOM.render(<Hello count={0}/>, document.getElementById('root'))
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.6/umd/react.production.min.js" integrity="sha256-3vo65ZXn5pfsCfGM5H55X+SmwJHBlyNHPwRmWAPgJnM=" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.6/umd/react-dom.production.min.js" integrity="sha256-qVsF1ftL3vUq8RFOLwPnKimXOLo72xguDliIxeffHRc=" crossorigin="anonymous"></script>

<div id='root'></div>

虽然这使得可以在类组件中使用钩子,但除非像我在此示例中那样迁移,否则我不建议您这样做。混合使用函数和类组件会使状态管理变得混乱。希望这可以帮助你。

最好的祝福


9

useState 是 React v16.8.0 中提供的钩子之一。它基本上可以让你将原本不带状态/功能性组件转换为具有自身状态的组件。

在最基本的层面上,它的使用方式如下:

const [isLoading, setLoading] = useState(true);

这样就可以调用setLoading并传递布尔值。 这是一种很酷的方式,使函数组件具有“有状态”的特性。

8

useState()是React中一个内置的钩子函数,它允许你在函数式组件中使用状态。在React 16.7之前,这是不可能的。

useState函数是一个内置钩子函数,可以从react包中导入。它允许你向函数式组件添加状态。使用useState钩子函数,你可以在函数组件内部创建一个状态片段,而无需切换到类组件。


6
感谢loelsonk,我已经这样做了。

const [dataAction, setDataAction] = useState({name: '', description: ''});

    const _handleChangeName = (data) => {
        if(data.name)
            setDataAction( prevState  => ({ ...prevState,   name : data.name }));
        if(data.description)
            setDataAction( prevState  => ({ ...prevState,   description : data.description }));
    };
    
    ....return (
    
          <input onChange={(event) => _handleChangeName({name: event.target.value})}/>
          <input onChange={(event) => _handleChangeName({description: event.target.value})}/>
    )


5
钩子是React v16.7.0-alpha中的新功能,useState是其中的“钩子”。useState()设置任何变量的默认值并在函数组件(PureComponent函数)中进行管理。例如:const [count,setCount] = useState(0);将计数器的默认值设置为0,并且您可以使用setCount增加减少该值。 onClick={() => setCount(count + 1)}将增加计数器的值。文档

3

React useState是React Hook,它允许你在函数组件中管理状态。

例如:

import React, { useState } from 'react'

const Example = () => {
  // create the "counter" state
  const [count, setCount] = useState(0)

  return (
    <div>
      <p>Button clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>
        Count + 1
      </button>
    </div>
  )
}

export default Example

使用useState,您可以轻松创建有状态的函数组件。旧的等效方式是使用类组件与Component类和setState

import React, { Component } from 'react'

class Example extends Component {
  constructor(props) {
    super(props)
    this.state = { count: 0 }
  }

  render() {
    const { count } = this.state
    return (
      <div>
        <p>Button clicked {count} times</p>
        <button onClick={() => this.setState({ count: count + 1 })}>
          Count + 1
        </button>
      </div>
    )
  }
}

export default Example

来源:

链接:


3

useState是一个钩子,它允许你将状态添加到功能组件中。它接受一个参数,即状态属性的初始值,并返回状态属性的当前值和一个可更新该状态属性的方法。
以下是一个简单的示例:

import React, { useState } from react    

function HookCounter {    
  const [count, setCount]= useState(0)    
    return(    
      <div>     
        <button onClick{( ) => setCount(count+1)}> count{count}</button>    
      </div>    
    )   
 }

useState接受状态变量的初始值,此处为零,并返回一对值。当前状态的值被称为count,一个可以更新状态变量的方法被称为setCount。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接