ReactJS - 使用 useState



useState 是一个基本的 React 钩子,它允许函数组件保持自己的状态,并根据状态变化重新渲染自身。useState的签名如下 -


 const [ <state>, <setState> ] = useState( <initialValue> )

哪里

  • initialValue − 状态的初始值。可以在任何类型(数字、字符串、数组和对象)中指定状态。
  • state − 表示状态值的变量。
  • setState − 函数变量,表示用于更新 useState 返回的状态的函数。

setState函数的签名如下:


 setState( <valueToBeUpdated> )

其中,valueToBeUpdated 是要为状态更新的值。设置和更新用户名的示例用法如下 -


// initialize the state
const [name, setName] = useState('John')

// update the state
setName('Peter)

特征

useState的显着特性如下 -

函数参数 − 它接受一个函数(返回初始状态)而不是初始值,并且在组件的初始渲染期间只执行一次函数。如果初始值的计算成本很高,这将有助于提高性能。


const [val, setVal] = useState(() => {
	 	var initialValue = null
	 	// expensive calculation of initial value
	 	return initialValue
})

验证先前的值 - 它检查状态的当前值和先前值,只有当它们不同时,React 才会渲染其子项并触发效果。这将提高渲染的性能。


// ...
setName('John') // update the state and rerender the component
// ...
// ...
setName('John') // does not fire the rendering of the children because the value of the state have not changed.
// ...

批处理多个状态更新 − 多个状态更新由 React 在内部进行批处理和处理。如果必须立即进行多个状态更新,那么可以使用 React 提供的特殊函数 flushSync,它将立即刷新所有状态更改。


 flushSync(() => setName('Peter'))

应用状态钩子

让我们创建一个登录表单组件,并使用 useState 钩子维护表单的值。

首先,使用以下命令创建并启动一个 React 应用程序,

create-react-app myapp
cd myapp
npm start

接下来,在组件文件夹(src/components/LoginForm.js)下创建一个 react 组件 LoginForm


import { useState } from 'react';
export default function LoginForm() {
	 	// render code
}

接下来,使用 useState 钩子创建两个状态变量,用户名和密码,如下所示 -


import { useState } from 'react';
export default function LoginForm() {
	 	const [username, setUsername] = useState('')
	 	const [password, setPassword] = useState('')
	 	
	 	// render code
}

接下来,创建一个函数来验证登录数据,如下所示 -


import { useState } from 'react';
export default function LoginForm() {
	 	const [username, setUsername] = useState('')
	 	const [password, setPassword] = useState('')
	 	
	 	let isEmpty = (val) => {
	 	 	 if(val == null || val == '') {
	 	 	 	 	return true;
	 	 	 } else {
	 	 	 	 	return false;
	 	 	 }
	 	}
	 	
	 	let validate = (e) => {
	 	 	 e.preventDefault()
	 	 	 if(!isEmpty(username) && !isEmpty(password)) {
	 	 	 	 	alert(JSON.stringify({
	 	 	 	 	 	 username: username,
	 	 	 	 	 	 password: password
	 	 	 	 	}))
	 	 	 } else {
	 	 	 	 	alert("Please enter username / password")
	 	 	 }
	 	}
	 	// render code
}

这里,isEmpty 是一个检查数据是可用还是空的函数。

接下来,呈现一个包含两个输入字段的登录表单,并使用状态变量(用户名和密码)、状态更新方法(setUsername 和 setPassword)和验证方法来处理表单。


import { useState } from 'react';
export default function LoginForm() {
	 	return (
	 	 	 <div style={{ textAlign: "center", padding: "5px" }}>
	 	 	 	 	<form name="loginForm">
	 	 	 	 	 	 <label for="username">Username: </label>
	 	 	 	 	 	 	 	<input id="username" name="username" type="text"
	 	 	 	 	 	 	 	value={username}
	 	 	 	 	 	 	 	onChange={(e) => setUsername(e.target.value)} />
	 	 	 	 	 	 <br />
	 	 	 	 	 	 <label for="password">Password: </label>
	 	 	 	 	 	 	 	<input id="password" name="password" type="password"
	 	 	 	 	 	 	 	value={password}
	 	 	 	 	 	 	 	onChange={(e) => setPassword(e.target.value)} />
	 	 	 	 	 	 <br />
	 	 	 	 	 	 <button type="submit" onClick={(e) => validate(e)}>Submit</button>
	 	 	 	 	</form>
	 	 	 </div>
	 	)
}

这里

  • onChange 使用 Hooks 返回的状态设置函数。
  • onClick 使用验证功能来验证并显示用户输入的数据。

LoginForm 组件的完整代码如下:


import { useState } from 'react';
export default function LoginForm() {
	 	const [username, setUsername] = useState('')
	 	const [password, setPassword] = useState('')
	 	
	 	let isEmpty = (val) => {
	 	 	 if(val == null || val == '') {
	 	 	 	 	return true;
	 	 	 } else {
	 	 	 	 	return false;
	 	 	 }
	 	}
	 	
	 	let validate = (e) => {
	 	 	 e.preventDefault()
	 	 	 if(!isEmpty(username) && !isEmpty(password)) {
	 	 	 	 	alert(JSON.stringify({
	 	 	 	 	 	 username: username,
	 	 	 	 	 	 password: password
	 	 	 	 	}))
	 	 	 } else {
	 	 	 	 	alert("Please enter username / password")
	 	 	 }
	 	}
	 	
	 	return (
	 	 	 <div style={{ textAlign: "center", padding: "5px" }}>
	 	 	 	 	<form name="loginForm">
	 	 	 	 	 	 <label for="username">Username: </label>
	 	 	 	 	 	 	 	<input id="username" name="username" type="text"
	 	 	 	 	 	 	 	value={username}
	 	 	 	 	 	 	 	onChange={(e) => setUsername(e.target.value)} />
	 	 	 	 	 	 <br />
	 	 	 	 	 	 <label for="password">Password: </label>
	 	 	 	 	 	 	 	<input id="password" name="password" type="password"
	 	 	 	 	 	 	 	value={password}
	 	 	 	 	 	 	 	onChange={(e) => setPassword(e.target.value)} />
	 	 	 	 	 	 <br />
	 	 	 	 	 	 <button type="submit" onClick={(e) => validate(e)}>Submit</button>
	 	 	 	 	</form>
	 	 	 </div>
	 	)
}

接下来,更新根应用程序组件,App.js如下所示,


import './App.css';
import HelloWorld from './components/HelloWorld';
import LoginForm from './components/LoginForm';
function App() {
	 	return (
	 	 	 <LoginForm />
	 	);
}
export default App;

接下来,打开浏览器并检查应用程序。应用程序将使用状态变量收集用户输入的数据,并使用验证函数进行验证。如果用户输入了正确的数据,它将显示如下所示的数据 -

Applying State Hook

否则,它将抛出如下所示的错误 -

Applying State Hook

对象作为状态

在基于类的状态管理中,setState 方法支持状态对象的部分更新。例如,让我们考虑登录表单数据作为对象保持在状态。

Applying State Hook


{
	 	username: 'John',
	 	password: 'secret'
}

使用 setState 更新用户名只会更新 state 对象中的用户名并保留密码字段。


this.setState({
	 	username: 'Peter'
})

在钩子中,setData(由 useState 返回的函数)将更新整个对象,如下所示 -


// create state
const [data, setDate] = useState({
	 	username: 'John',
	 	password: 'secret'
})
// update state - wrong
setData({
	 	username: 'Peter'
})

更新的状态没有密码字段,如下所示 -


{
	 	username: 'Peter'
}

为了解决这个问题,我们可以在javascript中使用spread运算符,如下所示 -


setData({
	 	...data,
	 	username: 'Peter'
})

让我们通过转换 LoginForm 组件来创建一个新组件,并使用对象状态变量,如下所示 -


import { useState } from 'react';
export default function LoginFormObject() {
	 	const [data, setData] = useState({})
	 	let isEmpty = (val) => {
	 	 	 if(val == null || val == '') {
	 	 	 	 	return true;
	 	 	 } else {
	 	 	 	 	return false;
	 	 	 }
	 	}
	 	let validate = (e) => {
	 	 	 e.preventDefault()
	 	 	 if(!isEmpty(data.username) && !isEmpty(data.password)) {
	 	 	 	 	alert(JSON.stringify(data))
	 	 	 } else {
	 	 	 	 	alert("Please enter username / password")
	 	 	 }
	 	}
	 	return (
	 	 	 <div style={{ textAlign: "center", padding: "5px" }}>
	 	 	 	 	<form name="loginForm">
	 	 	 	 	 	 <label for="username">Username: </label>
	 	 	 	 	 	 	 	<input id="username" name="username" type="text"
	 	 	 	 	 	 	 	value={data.username}
	 	 	 	 	 	 	 	onChange={(e) => setData( {...data, username: e.target.value} )} />
	 	 	 	 	 	 <br />
	 	 	 	 	 	 <label for="password">Password: </label>
	 	 	 	 	 	 	 	<input id="password" name="password" type="password"
	 	 	 	 	 	 	 	value={data.password}
	 	 	 	 	 	 	 	onChange={(e) => setData({...data, password: e.target.value})} />
	 	 	 	 	 	 <br />
	 	 	 	 	 	 <button type="submit" onClick={(e) => validate(e)}>Submit</button>
	 	 	 	 	</form>
	 	 	 </div>
	 	)
}

这里

  • State 在对象(数据)中维护。
  • setData 由 useState 钩子返回,并用作状态更新函数。
  • data.* 语法用于获取状态的详细信息。
  • …data 扩展运算符与 setData 函数一起使用以更新状态。

总结

useState hook 是在函数组件中进行状态管理的简单易行的方法。useState 可用于处理状态中的单个值或多个值。它既支持基本数据类型,也支持复杂对象。它允许多种状态设置功能(set*)和内部批处理,以简化流程。由于 useState 钩子的引入,函数组件终于得到了改进,可以做任何功能(从无状态到有状态)。