reactHooks中useState的使用小结

13062次浏览

前言

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在使用中的小结吧。有问题可以相互交流。

Tags: reactHooksusestatereact

相关文章: