React中的useState()是什么?


133

我目前正在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

Answers:


148

React钩子是访问React核心功能的一种新方法(仍在开发中),例如state无需使用类,在您的示例中,如果您想直接在处理函数中增加计数器而不在onClickprop中直接指定它,您可以可以做类似的事情:

...
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,和自定义挂钩。我可以深入了解有关钩子如何工作的详细信息,但是文档在解释状态钩子和其他钩子方面做得很好,希望能对您有所帮助。

更新: 挂钩不再是一个建议,因为版本16.8可以使用了,因此React网站上有一个部分可以回答一些FAQ


2
很好的类比,除了JavaScript从技术上讲没有元组数据类型
goonerify

好了,像元组一样使用了结构化的分配stackoverflow.com/a/4513061/6335029
NaveenDA

钩子异步吗?使用时setSomething,如果我之后再尝试something直接使用,则似乎仍然具有旧的价值……
Byron Coetsee

51

useState0.16.7版本中提供的内置react挂钩之一。

useState只能在功能组件内部使用。useState这是我们需要内部状态并且不需要实现更复杂的逻辑(例如生命周期方法)的方式。

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

返回一个有状态值,以及一个更新它的函数。

在初始渲染期间,返回的状态(状态)与作为第一个参数(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>

与类组件中的setState方法不同,useState不会自动合并更新对象。您可以通过将函数更新程序形式与对象传播语法结合使用来复制此行为:

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

有关更多信息,useState请参见官方文档


2
感谢您在示例中添加函数作为参数。
Juni Brosas

15

useStatehook 的语法很简单。

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>
   );
 }


这应该是公认的答案。简洁明了,具有良好的外部参考。
瓦伦

8

useState是React v16.8.0中可用的钩子之一。基本上,它使您可以将原本没有状态/功能的组件变成可以具有自己状态的组件。

在最基本的级别上,它是通过以下方式使用的:

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

然后,这使您可以调用setLoading传递布尔值。这是拥有“有状态”功能组件的一种很酷的方法。


7

useState()是一个React钩子。挂钩使在功能组件内部使用状态和可变性成为可能。

虽然您不能在类内部使用钩子,但可以使用功能之一包装类组件并使用其中的钩子。这是将组件从类迁移到函数形式的绝佳工具。这是一个完整的示例:

对于此示例,我将使用计数器组件。就是这个:

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>

它是具有计数状态的简单类组件,状态更新由方法完成。这是类组件中非常常见的模式。第一件事是使用具有相同名称的功能组件包装它,该组件将其所有属性委派给包装的组件。另外,您需要在函数return中呈现包装的组件。这里是:

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>

尽管这使得可以在类组件内部使用挂钩,但我不建议您这样做,除非您像在本示例中那样进行迁移。函数和类组件的混合会使状态管理变得一团糟。我希望这有帮助

最好的祝福


7

useState()是示例内置的React挂钩,可让您在功能组件中使用状态。在React 16.7之前这是不可能的。

useState函数是一个内置的挂钩,可以从react包中导入。它允许您向功能组件添加状态。使用功能组件内部的useState挂钩,您可以创建一条状态,而无需切换到类组件。


5

挂钩是React v16.7.0-alpha useState“挂钩” 中的一个新功能。useState()设置any变量的默认值并在函数组件(PureComponent函数)中进行管理。 ex : const [count, setCount] = useState(0);设置计数0的默认值。并且u可以使用setCountto incrementdecrement该值。onClick={() => setCount(count + 1)}增加计数值。DOC


4

谢谢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})}/>
    )


2

useState是一个钩子,可用于将状态添加到功能组件。它接受作为状态属性初始值的参数,并返回状态属性的当前值,以及能够更新该状态属性的方法。
以下是一个简单的示例:
import React, {useState} from react
function HookCounter {
const [count, stateCount]= useState(0)
return(
<div>
<button onClick{( ) => setCount(count+1)}> count{count} </button>
</div>
)
}

useState接受状态变量的初始值(在这种情况下为零),并返回一对值。状态的当前值称为count,可以更新状态变量的方法称为setCount。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.