React Hooks 几个简单API 的使用

262 阅读4分钟

前言

之前不是准备在学习 react 就是在学习 react 的路上,但都是在学了一段时间就因其他事情搁置了,也没有做相应的学习笔记,导致后面再用,还需要看 api,而且之前做的项目也都是用的比较基础的东西,所以在面试时并没有自信能够说出自己有丰富的 react 开发经验。所以现在一边复习之前学习的东西,一边对之前的系统进行 react 重构,做一个深入的了解和使用。

Hooks API

useState

useState 等同于 vue3reactive 或者 ref 方法,来生成响应式数据。不过 useState 会多创建一个修改该响应式数据的方法

   const [count, setCount] = useState(1);
   const updateCount = () => {
    setCount((pre: number) => pre + 1);
    // setCount 为异步更新,此时 count 还是之前的数据,我们可以通过 useEffect 来获取更新后的数据
   };

useEffect

useEffect 类似于 vue3 中的 watchcomputed , 可以监测到数据的变化。同时也可以作为生命周期函数使用。
1 当作为生命周期来使用时,可以对 useEffect 第二个参数以空数组监测

  useEffect(() => {
    console.log('作为生命周期函数执行');
  }, []);

2 第二个参数不传,监测所有的变化

  useEffect(() => {
    console.log('作为生命周期函数执行');
  });

3 对部分数据做监测,将监测数据加入数组即可

   const [count, setCount] = useState(1);
   const updateCount = () => {
    setCount((pre: number) => pre + 1);
   };
   useEffect(() => {
    console.log('作为生命周期函数执行');
  }, [count]);

4 返回值 useEffect 的第一个入参,最终返回 destory,它会在下一次 callback 执行之前调用,其作用是清除上次的 callback 产生的副作用,比如清除计时器等

  useEffect(() => {
   return () => {
        clearInterval(timer); // timer 为我们定义的计时器
        timer = null;
      };
  }, [xxx]);

useContext

类似于 vueprovide inject 通过在上层组件中传值,在子孙后代中使用。

通过 createContext 进行创建,在父组件中通过 Provider 进行数据提供,在子孙组件中使用 useContext 进行数据获取

// useContext
import { useContext, createContext, useState } from 'react';
const CountContext = createContext(-1);
function User() {
  const [count, setCount] = useState(1);
  const changeCount = () => {
    setCount(pre => pre + 1);
  };
  return (
    <div>
      <div>父组件count={count}</div>
      <button onClick={changeCount}>修改值</button>
      <CountContext.Provider value={count}>
        <UserChild />
      </CountContext.Provider>
      {/* .Provider 提供数据 */}
    </div>
  );
}

export default User;

const UserChild = () => {
  const count = useContext(CountContext);
  //接收数据
  return (
    <div>
      子组件展示count={count}
      {/* 展示数据 */}
      <Son></Son>
    </div>
  );
};

const Son = () => {
  const count = useContext(CountContext);
  return <div style={{ marginTop: 10 }}>孙组件获取到的count: {count}</div>;
};
// rsf

useImperativeHandle

useImperativeHandle 用于将子组件的方法暴露给父组件使用,等同于vue3 中 defineExpose。 使用方法:在父组件中对子组件进行 ref 绑定,在子组件中通过 useImperativeHandle 将子组件的 addChild 方法暴露出来,父组件通过 childrenRef.current.addChild 进行使用

// useReducer
import { useRef, forwardRef, useImperativeHandle } from 'react';
//父组件调用子组件方法
const Children = forwardRef((props: any, ref: any) => {
  const addChild = () => {
    console.log('父组件调用子组件 addChild 方法');
  };
  useImperativeHandle(ref, () => ({
    addChild,
  }));
  return (
    <div ref={ref}>
      <div>我是子组件</div>
    </div>
  );
});
function User() {
  const childrenRef: any = useRef(null);
  const handleChildren = () => {
    if (childrenRef.current.addChild) {
      childrenRef.current.addChild();
    }
  };
  return (
    <div>
      <div>User</div>
      <button onClick={handleChildren}>调用子组件方法</button>
      <Children ref={childrenRef}></Children>
    </div>
  );
}
export default User;

useMemo

缓存机制,在react 中父组件更新,会导致子组件重新渲染,为了节约性能,我们可以将改变的部分也提炼出来作为一个子组件,或者也可以通过useMemo进行组件缓存。

import { useMemo, useState } from 'react';
const usePow = (list: number[]) => {
  return useMemo(
    () =>
      list.map((item: number) => {
        return <div key={item}>{item}</div>;
      }),
    []
  );
};
function User() {
  const [flag, setFlag] = useState(false);
  const [powData, setPowData] = useState([1, 2, 3]);
  const setList = () => {
    setPowData([1, 2, 3]);
  };
  return (
    <div>
      <div>user</div>
      <div>数字集合:{usePow(powData)}</div>
      <br />
      <button onClick={() => setList()}>数组数据</button>
      状态{flag ? '真' : '假'}
      <br />
      <button onClick={() => setFlag(!flag)}>修改状态</button>
    </div>
  );
}
export default User;
//问题点,遍历的数组数据不能使用 useState 方式修改,如果将 usePow 函数放入 User 函数体内,数据每次渲染 usePow 会重新执行,也就失去了Memo的作用
// rsf

useReducer

简单来说,就是整合方法,使用方法和redux 类似,通过 type 进行相应的操作。但个人感觉有点多此一举,还不如直接通过传参方式来调用对应的方法。

// useReducer
import { useReducer } from 'react';
function User() {
  const [count, dispatch] = useReducer((state: number, action: any) => {
    switch (action?.type) {
      case 'add':
        return state + action?.payload;
      case 'sub':
        return state - action?.payload;
      default:
        return state;
    }
  }, 0);
  const changeCount = (type: number) => {
    if (type === 1) {
      dispatch({ type: 'add', payload: 11 });
    } else {
      dispatch({ type: 'sub', payload: 1 });
    }
  };
  return (
    <div>
      <div>user</div>
      <div>{count}</div>
      <br />
      <button onClick={() => changeCount(1)}>增加值</button>
      <br />
      <br />
      <button onClick={() => changeCount(2)}>减少值</button>
    </div>
  );
}
export default User;

结语

明显看的出来这篇有点敷衍了事了,先完成 kpi 吧,等下个月再进行更新补充,此时2023年7月31号21点45,还有一篇文章未完成,就如考试就剩十五分钟了,作文还没写。加把劲,凌晨前结束下一篇