前言
reactHooks在使用useState中遇到了一些问题,今天这篇文章主要介绍useState的一些使用,具体useState的一些简单的用法,本文就不举例详细说明了,就说一下useState使用过程中的坑吧。
一、只能处理简单的状态
随便举个例子,如下:
const [items, setItems] = useState([]);
我一开始以为setItems的功能就类似原来react中setState,但是当我用setItems处理复杂数组对象的时候,会报错。处理复杂状态要改用useReducer()
setItems在设置状态的时候,只有简单的String,Boolean等可以直接setItems(XXX),在数组或者对象的时候,要通过如下方式:
setItems([
...items,
{
id: items.length,
value: Math.random() * 100
}
]);
setItems 更新 state 不会将旧值“合并” - 它会使用新值覆盖state。 这与this.setState在类中的工作方式不同。
针对复杂对象,例如:
let haoroomsBlog=[
{name:'haorooms博客',value:1,type:'blog',children:[{name:'article',value:'haorooms内容'}]},
{name:'haorooms博客资源库',value:2,type:'resource',children:[{name:'resource',value:'haorooms内容'}]}
]
假如我们需要对children里面的内容做增删改,那么,我们直接用上面的方式修改,也是有问题的。这里我们需要改成useReducer方式。 对上面可以改造如下:
const haoroomsBlog = {name:'haorooms博客',value:1,type:'blog',children:[{name:'article',value:'haorooms内容'}]},
export function haoroomsReducer(state, action) {
const data = { ...state }
switch (action.type) {
case 'ADDCHILD': {
data.children.push({ id: 'test', name: action.content })
return {
...state,
children: data.children
}
}
case 'DELETE': {
data.children.splice(action.content, 1)
return {
...state,
children: data.children
}
}
default:
return state
}
}
const [stateHaorooms, dispatch] = useReducer(haoroomsReducer, haoroomsBlog)
// 使用如下:
dispatch({ type: 'ADDCHILD', content:'haorooms blog 内容' })
二、调用位置
在使用useState() Hook 时,必须遵循 Hook 的规则
仅顶层调用 Hook :不能在循环,条件,嵌套函数等中调用useState()。在多个useState()调用中,渲染之间的调用顺序必须相同。
仅从React 函数调用 Hook:必须仅在函数组件或自定义钩子内部调用useState()。
例如:
function haorooms() {
// Good
const [on, setOn] = useState(false);
const [count, setCount] = useState(1);
// ...
这样是对的
如下是错误的:
function Switch({ isSwitchEnabled }) {
if (isSwitchEnabled) {
// Bad
const [on, setOn] = useState(false);
}
// ...
}
在嵌套函数中调用useState()也是不对的
function Switch() {
let on = false;
let setOn = () => {};
function enableSwitch() {
// Bad
[on, setOn] = useState(false);
}
return (
<button onClick={enableSwitch}>
Enable light switch state
</button>
);
}
过时的状态
例如如下代码:
function DelayedCount() {
const [count, setCount] = useState(0);
const handleClickAsync = () => {
setTimeout(function delay() {
setCount(count + 1);
}, 3000);
}
return (
<div>
{count}
<button onClick={handleClickAsync}>Increase async</button>
</div>
);
}
原因是闭包的问题,闭包(例如事件处理程序,回调)可能会从函数组件作用域中捕获状态变量。 由于状态变量在渲染之间变化,因此闭包应捕获具有最新状态值的变量。否则,如果闭包捕获了过时的状态值,则可能会遇到过时的状态问题。
解决方案:
使用函数方法来更新count状态:
function DelayedCount() {
const [count, setCount] = useState(0);
const handleClickAsync = () => {
setTimeout(function delay() {
setCount(count => count + 1);
}, 3000);
}
return (
<div>
{count}
<button onClick={handleClickAsync}>Increase async</button>
</div>
);
}
这样就可以了。
简单数组或者对象的修改
对应层级相对简单的数组,或者对象,我们可以用useState,例如如下:
import React, { useState } from 'react';
function FavoriteMovies() {
const [movies, setMovies] = useState([{ name: 'Heat' }]);
const add = movie => setMovies([...movies, movie]);
const remove = index => {
setMovies([
...movies.slice(0, index),
...movies.slice(index + 1)
]);
}
return (
// Use add(movie) and remove(index)...
);
}
小结
以上就是hooks 的useState在使用中的小结吧。有问题可以相互交流。