React Hooks使用

一、React Hooks 介绍

1.1 React Hooks 是⽤来做什么的

对函数型组件进⾏增强, 让函数型组件可以存储状态, 可以拥有处理副作⽤的能⼒.
让开发者在不使⽤类组件的情况下, 实现相同的功能.

副作用是指:只要不是将数据转化为视图的代码。比如:获取Dom元素,为Dom元素添加事件,ajax请求等等

二、类组件的不足

1. 缺少逻辑复⽤机制

为了复⽤逻辑增加⽆实际渲染效果的组件,增加了组件层级 显示⼗分臃肿
增加了调试的难度以及运⾏效率的降低

2. 类组件经常会变得很复杂难以维护

将⼀组相⼲的业务逻辑拆分到了多个⽣命周期函数中
在⼀个⽣命周期函数内存在多个不相⼲的业务逻辑

3. 类成员⽅法不能保证this指向的正确性

三、使用useState让函数组件保存状态

Hooks 意为钩⼦, React Hooks 就是⼀堆钩⼦函数, React 通过这些钩⼦函数对函数型组件进⾏增强, 不同的钩⼦函数提供了不同的功能.

useState()
useEffects()
useReducer()
useRef()
useCallback()
useContext()
useMemo()

1、useState()

在这里插入图片描述
在这里插入图片描述

  1. 接收唯⼀的参数即状态初始值. 初始值可以是任意数据类型.
  2. 返回值为数组. 数组中存储状态值和更改状态值的⽅法. ⽅法名称约定以set开头, 后⾯加上状态名称.
  3. ⽅法可以被调⽤多次. ⽤以保存不同状态值.
  4. 参数可以是⼀个函数, 函数返回什么, 初始状态就是什么, 函数只会被调⽤⼀次, ⽤在初始值是动态值的情况

设置状态值⽅法的参数可以是⼀个值也可以是⼀个函数
设置状态值⽅法的⽅法本身是异步的

在这里插入图片描述

2、useReducer()

useReducer是另⼀种让函数组件保存状态的⽅式

在这里插入图片描述

3、useContext

没有用useContext之前传参

在这里插入图片描述
使用useContext优化

在这里插入图片描述
代码简洁很多

4、useEffect

让函数型组件拥有处理副作⽤的能⼒. 类似⽣命周期函数

可以把 useEffect 看做 componentDidMount, componentDidUpdatecomponentWillUnmount 这三个函数的组合.

useEffect(() => {}) => componentDidMount, componentDidUpdate
useEffect(() => {}, []) => componentDidMount
useEffect(() => () => {}) => componentWillUnMount

监听页面滚动

在这里插入图片描述
组件销毁取消监听

卸载组件↓
在这里插入图片描述

只有指定数据发⽣变化时触发effect

在这里插入图片描述

5、useMemo()

useMemo 的⾏为类似Vue中的计算属性, 可以监测某个值的变化, 根据变化值计算新值.
useMemo 会缓存计算结果. 如果监测值没有发⽣变化, 即使组件重新渲染, 也不会重新计算. 此⾏为可以有助于避免在每个渲染上进⾏昂贵的计算

在这里插入图片描述
在这里插入图片描述

6、memo ⽅法

性能优化, 如果本组件中的数据没有发⽣变化, 阻⽌组件更新. 类似类组件中的 PureComponent 和 shouldComponentUpdate

在这里插入图片描述

在这里插入图片描述

7、useCallback()

在这里插入图片描述
Foo组件的状态即使不变化也被重新渲染。

解决↓

性能优化, 缓存函数, 使组件重新渲染时得到相同的函数实例.

在这里插入图片描述

8、useRef()

1、获取DOM元素对象

在这里插入图片描述

2、保存数据 (跨组件周期)

即使组件重新渲染, 保存的数据仍然还在. 保存的数据被更改不会触发组件重新渲染.

场景一、下面定时器不会被清除,因为数据变视图会更细,timerId都是重置为null
在这里插入图片描述
解决:在这里插入图片描述

四、自定义hook

⾃定义 Hook 是标准的封装和共享逻辑的⽅式.
⾃定义 Hook 是⼀个函数, 其名称以 use 开头.
⾃定义 Hook 其实就是逻辑和内置 Hook 的组合

在这里插入图片描述
在这里插入图片描述

五、React 路由 Hooks

react-router-dom 路由提供的钩⼦函数

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

六、useState钩子函数的实现原理

let state = [];
let setters = [];
let stateIndex = 0;

function createSetter (index) {
  return function (newState) {
    state[index] = newState;
    render ();
  }
}

function useState (initialState) {
  state[stateIndex] = state[stateIndex] ? state[stateIndex] : initialState;
  setters.push(createSetter(stateIndex));
  let value = state[stateIndex];
  let setter = setters[stateIndex];
  stateIndex++;
  return [value, setter];
}

function render () {
  stateIndex = 0;
  effectIndex = 0;
  ReactDOM.render(<App />, document.getElementById('root'));
}

function App() { 
  const  [count, setCount] = useState(0)
  const [name, setName] = useState('张三')
  return <div>
    {count}
    {name}
  </div>
}

七、useEffect钩子函数实现原理

// 上一次的依赖值
let prevDepsAry = [];
let effectIndex = 0;
function useEffect(callback, depsAry) {
  // 判断callback是不是函数
  if (Object.prototype.toString.call(callback) !== '[object Function]') throw new Error('useEffect函数的第一个参数必须是函数');
  // 判断depsAry有没有被传递
  if (typeof depsAry === 'undefined') {
    // 没有传递
    callback();
  } else {
    // 判断depsAry是不是数组
    if (Object.prototype.toString.call(depsAry) !== '[object Array]') throw new Error('useEffect函数的第二个参数必须是数组');
    // 获取上一次的状态值
    let prevDeps = prevDepsAry[effectIndex];
    // 将当前的依赖值和上一次的依赖值做对比 如果有变化 调用callback
    let hasChanged = prevDeps ? depsAry.every((dep, index) => dep === prevDeps[index]) === false : true;
    // 判断值是否有变化
    if (hasChanged) {
      callback();
    }
    // 同步依赖值
    prevDepsAry[effectIndex] = depsAry;
    effectIndex++;
  }
}

八、useReducer钩子实现原理

function useReducer (reducer, initialState) {
  const [state, setState] = useState(initialState);
  function dispatch (action) {
    const newState = reducer(state, action);
    setState(newState);
  }
  return [state, dispatch];
}

function App() {
  function reducer (state, action) {
    switch (action.type) {
      case 'increment':
        return state + 1;
      case 'decrement':
        return state - 1;
      default:
        return state;
    }
  }
  const [count, dispatch] = useReducer(reducer, 0);
  return <div>
    {count}
    <button onClick={() => dispatch({type: 'increment'})}>+1</button>
    <button onClick={() => dispatch({type: 'decrement'})}>-1</button>
  </div>;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值