218

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

14 回答 14

237

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

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

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

和点击:

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

让我们快速解释一下这一行发生了什么:

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

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

我写了一篇关于钩子的完整文章,其中包含多个示例(包括计数器),例如这个 codepen,我使用了useState, useEffect,useContextcustom hooks。我可以详细了解钩子在这个答案上的工作原理,但是文档很好地详细解释了状态钩子和其他钩子,希望对您有所帮助。

更新: Hooks 不再是一个提案,因为16.8版它们现在可以使用,React 网站中有一个部分回答了一些常见问题解答

于 2018-11-06T05:26:37.810 回答
76

useState是版本中可用的内置反应钩子之一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>

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

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

更多关于useState查看官方文档

于 2018-12-02T21:02:51.437 回答
22

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

于 2018-11-06T05:20:22.117 回答
9

useState是 React v16.8.0 中可用的钩子之一。它基本上可以让您将原本无状态/功能性的组件转换为可以拥有自己状态的组件。

在最基本的层面上,它是这样使用的:

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

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

于 2018-11-06T05:44:43.240 回答
8

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

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

于 2018-11-06T06:33:02.910 回答
8

useState()是一个 React 钩子。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>

虽然这使得在类组件中使用钩子成为可能,但我不建议您这样做,除非您像我在此示例中所做的那样进行迁移。混合函数和类组件会使状态管理变得一团糟。我希望这有帮助

最好的祝福

于 2019-08-06T00:25:39.377 回答
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})}/>
    )

于 2019-12-17T10:43:44.983 回答
5

React v16.7.0-alpha useState钩子是“钩子”中的一个新功能。useState()设置任意变量的默认值并在函数组件(PureComponent 函数)中管理。 ex : const [count, setCount] = useState(0);设置计数 0 的默认值。您可以使用setCounttoincrementdecrement该值。onClick={() => setCount(count + 1)}增加计数值。文档

于 2018-11-06T05:09:26.613 回答
3

useState 是一个钩子,可让您将状态添加到功能组件。它接受一个参数,该参数是 state 属性的初始值,并返回 state 属性的当前值和一个能够更新该 state 属性的方法。
下面是一个简单的例子:

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。

于 2020-05-16T18:35:41.190 回答
2

基本上React.useState(0)神奇地看到它应该返回元组countsetCount(改变的方法count)。参数useState采用设置的初始值count

  const [count, setCount] = React.useState(0);
  const [count2, setCount2] = React.useState(0);

  // increments count by 1 when first button clicked
  function handleClick(){
    setCount(count + 1);
  } 

  // increments count2 by 1 when second button clicked
  function handleClick2(){
    setCount2(count2 + 1);
  } 

  return (
    <div>
      <h2>A React counter made with the useState Hook!</h2>
      <p>You clicked {count} times</p>
      <p>You clicked {count2} times</p>
      <button onClick={handleClick}>
        Click me
      </button> 
      <button onClick={handleClick2}>
        Click me2
      </button>
  );

基于 Enmanuel Duran 的示例,但显示了两个计数器并将 lambda 函数编写为普通函数,因此有些人可能更容易理解。

于 2020-09-20T06:36:02.633 回答
2

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

来源:

链接:

于 2021-04-02T16:54:19.923 回答
2

让我们以简单的方式非常容易地理解 useState

假设我们有反应代码:-

index.js

import React from 'react';
import ReactDOM from 'react-dom';
import Test from './components/Test.jsx'
ReactDOM.render(
  <div>
      <Test />
  </div>
,
  document.getElementById('root')
);

测试.jsx

import React from "react";

function Test() {
  var x = 5;
  function update() {
    console.log(x);
    return x++;
  }
  return (
    <div>
      <h1>{x}</h1>
      <button onClick={update}>click</button>
    </div>
  );
}
export default Test;

在这里,页面将显示5,虽然我们通过单击按钮调用更新功能,因为我们更新 x 但不是在 h1 标签之间,但实际上,每当我们点击时 x 都会不断变化,但它可以在控制台上看到

单击此链接查看结果并检查控制台

在这里 usState 神奇地工作,

使用useState的 Test.jsx

import React, { useState } from "react";

function Test() {
  var x = 5;
  const [value, setValue] = useState(x);

  function update() {
    setValue(value + 1);
  }

  return (
    <div>
      <h1>{value}</h1>
      <button onClick={update}>click</button>
    </div>
  );
}
export default Test;

点击此链接查看结果

在这里,通过单击按钮,值将不断更新,因为这里我们使用useState,它是一个函数,它返回两个东西一个是当前状态值,另一个是函数,如果我们将任何值传递给这个函数,它将更新当前状态值并且当前状态值在它使用的所有地方更新其值,而无需编写任何额外的代码。

于 2021-07-21T11:09:07.047 回答
1

上面提供的答案很好,但让我插话,useState是异步的,所以如果你的下一个状态取决于你以前的状态,最好你传递useState一个回调。请参见下面的示例:

import { useState } from 'react';

function Example() {
    const [count, setCount] = useState(0);

  return (
    <div>
      <p>You clicked {count} times</p>
      // passing a callback to useState to update count
      <button onClick={() => setCount(count => count + 1)}>
        Click me
      </button>
    </div>
  );
}

如果您的新状态依赖于旧状态的计算,这是推荐的方法。

于 2020-09-28T14:55:54.487 回答
0

useState 是一个 Hook,它允许您在功能组件中拥有状态变量。

React 中有两种类型的组件:类和函数式组件。

类组件是从 React.Component 扩展而来的 ES6 类,可以具有状态和生命周期方法:

class Message extends React.Component {
constructor(props) {
super(props);
this.state = {
  message: ‘’    
 };
}

componentDidMount() {
/* ... */
 }

render() {
return <div>{this.state.message}</div>;
  }
}

函数式组件是只接受参数作为组件属性并返回有效 JSX 的函数:

function Message(props) {
  return <div>{props.message}</div>
 }
// Or as an arrow function
const Message = (props) =>  <div>{props.message}</div>

如您所见,没有状态或生命周期方法。

于 2020-12-08T10:16:29.953 回答