React Hooks使用实例

使用hooks注意事项:

  • 不能将 hooks 放在循环、条件语句或者嵌套方法内。react 是根据 hooks 出现顺序来记录对应状态的。
  • 只在 function 组件和自定义 hooks 中使用 hooks。

  • 命名规范:
    • useState 返回数组的第二项以 set 开头(仅作为约定)。

    • 自定义 hooks 以 use 开头(可被 lint 校验)。

React 中提供的 hooks:

  • useState:setState

  • useReducer:setState,同时 useState 也是该方法的封装

  • useRef: ref

  • useImperativeHandle: 给 ref 分配特定的属性

  • useContext: context,需配合 createContext 使用

  • useMemo: 可以对 setState 的优化

  • useCallback: useMemo 的变形,对函数进行优化

  • useEffect: 类似 componentDidMount/Update, componentWillUnmount,当效果为 componentDidMount/Update 时,总是在整个更新周期的最后(页面渲染完成后)才执行

  • useLayoutEffect: 用法与 useEffect 相同,区别在于该方法的回调会在数据更新完成后,页面渲染之前进行,该方法会阻碍页面的渲染

  • useDebugValue:用于在 React 开发者工具中显示自定义 hook 的标签

1.使用useState实现改变值

  • useState 有一个参数,该参数可传如任意类型的值或者返回任意类型值的函数

  • useState 返回值为一个数组,数组的第一个参数为我们需要使用的 state,第二个参数为一个setter函数,可传任意类型的变量,或者一个接收 state 旧值的函数,其返回值作为 state 新值。

在index.tsx中的代码如下:

import React, { useState } from 'react';

export default () => {
  const [price, setPrice] = useState(0)
  const [count, setCount] = useState(()=>{
    const price = 5
    return price;
  })
  return (
    
单价:{price}元
数量:{count}个
); }

效果如图:React Hooks使用实例_第1张图片通过setPrice和setCount改变price和count的值;

2.使用useContext传递值

设计目的: context 设计目的是为共享那些被认为对于一个组件树而言是“全局”的数据。

使用场景: context 通过组件树提供了一个传递数据的方法,从而避免了在每一个层级手动的传递 props 属性

注意点: 不要仅仅为了避免在几个层级下的组件传递 props 而使用 context,它是被用于在多个层级的多个组件需要访问相同数据的情景。

useContext该函数接收一个 Context 类型的参数(就是包裹了 Provider 那个对象),返回 Provider 中的 value 属性对象的值。

React 组件允许 Consumers 订阅 context 的改变。而 Provider 就是发布这种状态的组件,该组件接收一个 value 属性传递给 Provider 的后代 Consumers。一个 Provider 可以联系到多个 Consumers。Providers 可以被嵌套以覆盖组件树内更深层次的值。

index.tsx:

import React, { useState, createContext } from 'react';
import Child from './index2';

export const CountText = createContext(4);

export default () => {
  const [price, setPrice] = useState(0)
  const [count, setCount] = useState(()=>{
    const price = 5
    return price
  })
  return (
    
单价:{price}元
数量:{count}个
); }

index2.tsx:

import React, { useContext } from 'react';
import { CountText } from './index'
export default props => {
  
  let count = useContext(CountText)
  return (
    
这是从props拿到的单价:{props.Price}
这是从CountText拿到的数量:{count}
) }

效果如下:React Hooks使用实例_第2张图片除了useContext进行传值props依旧可以传值传回调。

3.useReducer使用方法

useState 的替代方案。它接收一个形如 (state, action) => newState 的 reducer,并返回当前的 state 以及与其配套的 dispatch 方法。

  • useReducer 接收三个参数,第一个参数为一个 reducer 函数,第二个参数是reducer的初始值,第三个参数为可选参数,值为一个函数,可以用来惰性提供初始状态。这意味着我们可以使用使用一个 init 函数来计算初始状态/值,而不是显式的提供值。如果初始值可能会不一样,这会很方便,最后会用计算的值来代替初始值。
  • reducer 接受两个参数一个是 state 另一个是 action ,用法原理和 redux 中的 reducer 一致。
  • useReducer 返回一个数组,数组中包含一个 state 和 dispath,state 是返回状态中的值,而 dispatch 是一个可以发布事件来更新 state 的函数。
import React, { useReducer } from 'react';
export default function ReducerDemo() {
  const [count, dispatch] = useReducer((state, action) => {
    switch (action.type) {
      case 'add':
        return state + 1;
      case 'sub':
        return state - 1;
      default:
        return state;
    }
  }, 1)
  function addNum() {
    dispatch({
      type: 'add'
    })
  }
  function subNum() {
    dispatch({
      type: 'sub'
    })
  }
  return (
    
现在的数值是{count}
) }

同时,useReucer 也是 useState 的内部实现,useState 和 useReucer 的实现原理:

let memoizedState
function useReducer(reducer, initialArg, init) {
    let initState = void 0
    if (typeof init === 'function') {
        initState = init(initialArg)
    } else {
        initState = initialArg
    }
    function dispatch(action) {
        memoizedState = reducer(memoizedState, action)
    }
    memoizedState = memoizedState || initState
    return [memoizedState, dispatch]
}

function useState(initState) {
    return useReducer((oldState, newState) => {
        if (typeof newState === 'function') {
            return newState(oldState)
        }
        return newState
    }, initState)
}

4.useEffect

useEffect方法接收传入两个参数:

  • 回调函数:在第组件一次render和之后的每次update后运行,React保证在DOM已经更新完成之后才会运行回调。
  • 状态依赖(数组):当配置了状态依赖项后,只有检测到配置的状态变化时,才会调用回调函数。

注意:useEffect的第二个参数必须传空数组,这样它就等价于只在componentDidMount的时候执行。如果不传第二个参数的话,它就等价于componentDidMount和componentDidUpdate

useEffect(() => {
  //每次render后执行
  return () => {
  //当前 effect 之前对上一个 effect 进行清除
  }
})
useEffect(() => {
  //仅在第一次render后执行
  return () => {
  //组件卸载前执行
  }
}, [])
useEffect(() => {
  //arr变化后,render后执行
  return () => {
  //下一useEffect运行前执行
  }
}, arr)

 回调返回值

useEffect的第一个参数可以返回一个函数,当页面渲染了下一次更新的结果后,执行下一次useEffect之前,会调用这个函数。这个函数常常用来对上一次调用useEffect进行清理。

import React, { useState,useEffect } from 'react';

export default () => {
  const [price, setPrice] = useState(0)
  useEffect(() => {
    console.log('执行...', price);
    return () => {
      console.log('清理...', price);
    }
  }, [price]);
  return (
    
单价:{price}元
); }

输出结果如图:React Hooks使用实例_第3张图片 useEffect中返回的是一个函数,这形成了一个闭包,这能保证我们上一次执行函数存储的变量不被销毁和污染。

清除副作用

const [value, setValue] = useState()
useEffect(() => {
    const timer1 = setTimeout(() => {
      console.log('send')
      console.log(value)
    }, 2000)
    return () => {
      console.log('clearLastSend')
      clearTimeout(timer1)
    }
  }, [value])
 setValue(e.target.value)} />

5.使用useRef获取dom的ref

import React, { useRef } from 'react';
export default () => {
  const inputRef = useRef(null);
  const onButtonClick = () => {
    console.log(inputRef.current.value)
  };
  return (
    
); }

 

你可能感兴趣的:(react,hooks)