【ahooks源码解读04】state相关hooks之useSetState

state相关hook清单

根据梳理,目前的ahooks版本3.7.7提供了state相关的hook共计16个,我们会分几个篇章来分别看下,这篇我们分析下useSetStateuseState一些基本要点

image-20231211143323717

前置知识点

useState

我们在看ahooks中state相关hook前,还是在回顾下React中基础的useState的使用

定义

useState is a React Hook that lets you add a state variable to your component.

说人话就是 useState能给函数式组件引入状态变量,因为纯函数组件本身,在没有hook的加持下,只支持根据Props的联动UI展示

基本使用

scss 复制代码
const [state, setState] = useState(initData)

参数

  • initialState:是一个你希望的初始值,可以是任何类型,但是如果是函数的话,它的参数将会被忽略

    • 如果initialState是函数,应当是个没有参数的纯函数.React会以函数的返回值作为初始State

返回值

数组形式,第一个参数是state,第二个参数是set函数,不再赘述

注意点

除了hook使用的基本规定,就是只能在顶层函数使用,不能在if,循环中使用外,在严格模式的开发模式中,initial的function会调用两次,目的就是看下这个function是不是纯函数,当然这个特性不会在production模式中生效。其实目的也很简单,就是帮助我们发现一些因为不是纯函数导致的问题

简单讲下纯函数的定义

css 复制代码
function A(a,b){
 return a+b
}
// 对于特定的函数A,只要参数列表固定,多次调用该函数,返回值应当是一样的
// A(1,2);
// A(1,2);
// A(1,2);

哪些情况就不是纯函数了,比如内部有随机数,异步获取IO【网络,系统API】等等,因为这些会导致相同的函数,在不同的时刻或者条件下返回的值是不一样的

useState使用和其他问题就不再赘述了,大家可以看下官网定义或者其他博主的分享

useSetState

作用

管理 object 类型 state 的 Hooks,用法与 class 组件的 this.setState 基本一致。

凡事先说干嘛用的,这里有个非常值得注意的点,就是有了useState,ahook为什么还要封装个useSetState,这个Set的含义是什么

究其原因,我们根据ahook的定义跟Class 模式下的this.setState对比下

php 复制代码
// 伪代码
const [a,setA]=useState({name:'张三',age:14});

// 如果我们在某个地方,想把age改成18,setA({age:18})的话 会发生什么??
typescript 复制代码
import React from 'react';
import { useSetState } from 'ahooks';

interface State {
  hello: string;
  [key: string]: any;
}

export default () => {
  const [state, setState] = useSetState<State>({
    hello: '',
  });
  const [state1,setState1]=React.useState({name:'s',age:14} as any);

  return (
    <div>
      <pre>{JSON.stringify(state, null, 2)}</pre>
      <pre>{JSON.stringify(state1, null, 2)}</pre>

      <p>
        <button type="button" onClick={() =>
          setState({hello: 'world'})}>
          set hello
        </button>
        <button type="button" onClick={() => setState({ foo: 'bar' })} style={{ margin: '0 8px' }}>
          set foo
        </button>
          <button onClick={()=> setState1({age: 18})}>测试useState</button>
      </p>
    </div>
  );
};

image-20231211152816305

结果说下,就是a整个就变成了{age:18},而不是this.setState后的{name:'张三',age:18},这个就跟this.setState区别的就在于少了一个针对State的Merge操作

然后我们再来看useSetState的源码就很清楚了

typescript 复制代码
import { useCallback, useState } from 'react';
import { isFunction } from '../utils';

// useSetState的第二个返回值,set操作函数的ts类型声明
export type SetState<S extends Record<string, any>> = <K extends keyof S>(
  state: Pick<S, K> | null | ((prevState: Readonly<S>) => Pick<S, K> | S | null),
) => void;

// Record,ts内建键值对式类型工具
const useSetState = <S extends Record<string, any>>(
  initialState: S | (() => S),
): [S, SetState<S>] => {
  const [state, setState] = useState<S>(initialState);

  const setMergeState = useCallback((patch) => {
    setState((prevState) => {
      // 判断set动作的参数是否为函数
      const newState = isFunction(patch) ? patch(prevState) : patch;
      // 进行merge操作
      return newState ? { ...prevState, ...newState } : prevState;
    });
  }, []);

  return [state, setMergeState];
};

export default useSetState;

因此我们可以总结下useSetState可以让我们将一类状态变量放到一个state中,避免多次使用useState创建多个状态变量和对应的更新操作

下篇预告

接下来我们读源码的进度会尽量加快一些,下一篇介绍下useSetuseMap的使用和源码,顺便巩固下ES6中set和map这两种数据结构

关注我,敬请期待

本文使用 markdown.com.cn 排版

相关推荐
崔庆才丨静觅5 分钟前
hCaptcha 验证码图像识别 API 对接教程
前端
passerby60611 小时前
完成前端时间处理的另一块版图
前端·github·web components
掘了1 小时前
「2025 年终总结」在所有失去的人中,我最怀念我自己
前端·后端·年终总结
崔庆才丨静觅1 小时前
实用免费的 Short URL 短链接 API 对接说明
前端
崔庆才丨静觅1 小时前
5分钟快速搭建 AI 平台并用它赚钱!
前端
崔庆才丨静觅2 小时前
比官方便宜一半以上!Midjourney API 申请及使用
前端
Moment2 小时前
富文本编辑器在 AI 时代为什么这么受欢迎
前端·javascript·后端
崔庆才丨静觅2 小时前
刷屏全网的“nano-banana”API接入指南!0.1元/张量产高清创意图,开发者必藏
前端
剪刀石头布啊2 小时前
jwt介绍
前端
爱敲代码的小鱼2 小时前
AJAX(异步交互的技术来实现从服务端中获取数据):
前端·javascript·ajax