React17 Hooks(一)

242 阅读3分钟

1. 什么是 Hook?

Hook 就是一个特殊的函数。
在React中只有两个地方可以使用Hook:
    --- 1. 函数式组件中
    --- 2. 自定义Hook中

2. useState

useState Hook就是让函数式组件保存自己状态的函数。

const [numState,setNumState] = useState(10)
<div>
    <p>{numState}</p>
    <button onClick={() =>{setNumState(numState+1)}}>+</button>
</div>

3. useEffect

useEffect Hook可以看做(组件挂载,组件更新,组件即将卸载)三个生命周期函数的组合。
特点:可以设置依赖,只有依赖发生变化的时候才执行。
优势: 1. 默认情况下只要数据发生变化就会调用。
      2. 对比类组件生命周期方法优势:易于拆分。
      
function Child() {
  return <div>Child子组件</div>;
}

export default function UseEffect() {
  const [showState,setShowState] = useState(true)

  useEffect(() =>{
      // 组件被挂载执行
      console.log('修改DOM');
  })
  useEffect(() =>{
      // 组件被挂载执行
      console.log('注册监听');
      return () =>{
          // 组件将被卸载执行
          console.log('移出监听');
      }
  })
  useEffect(() =>{
      // 组件被挂载执行
      console.log('发送网络请求');
  })  
  return (
    <div>
        {showState &&  <Child />}
        <button onClick={() =>{setShowState(!showState)}}>切换</button>
    </div>
  );
}

4. useContext

useContext Hook是给函数式组件提供数据共享的函数

// jsx文件
import React, { createContext, useContext } from "react";

const UserContext = createContext({});
const ColorContext = createContext({});

function Child() {
  // 子组件通过 useContext(使用数据)  
  const user = useContext(UserContext);
  const color = useContext(ColorContext);
  return (
    <div>
        <p>Child子组件</p>
        <p>{user.name}</p>
        <p>{user.age}</p>
        <p>{color.color}</p>
    </div>
  )
}

export default function UseContext() {
  return (
    <div>
      {/* 父组件通过 Provider(生产数据) */}
      <UserContext.Provider value={{ name: "liu", age: 24 }}>
        <ColorContext.Provider value={{ color: "red" }}>
          <Child />
        </ColorContext.Provider>
      </UserContext.Provider>
    </div>
  );
}

5. useReducer

useReducer Hook是useState的一种替代方案,可以复用操作数据的逻辑代码。
注意点:不是用来替代Redux的。

// jsx文件
import React, { useReducer, useState } from 'react';

 /*
    useReducer接受的参数:
        第一个参数:处理数据的函数
        第二个参数:保存的默认值
    useReducer返回值:
        第一个元素:保存的数据
        第二个元素:dispatch函数    
  */ 
function reducer(state,action) {
    switch(action.type) {
        case 'ADD':
            return {...state,num: state.num + 1}
        case 'SUB':
            return {...state,num: state.num + 1}
        default:
            return state        
    }
}

function Child1() {
    // const [numState,setNumState] = useState(10);
    const [state,dispatch] = useReducer(reducer,{num: 10})
    return (
        <div>
            <p>Child1子组件</p>
            <p>{state.num}</p>
            <button onClick={() =>{dispatch({type: 'ADD'})}}>+</button>
            <button onClick={() =>{dispatch({type: 'SUB'})}}>-</button>
            {/* <button onClick={() =>{setNumState(numState+1)}}>+</button>
            <p>{numState}</p>
            <button onClick={() =>{setNumState(numState-1)}}>-</button> */}
        </div>
    )
}

function Child2() {
    // const [numState,setNumState] = useState(20);
    const [state,dispatch] = useReducer(reducer,{num: 20})
    return (
        <div>
             <p>Child2子组件</p>
             <p>{state.num}</p>
             <button onClick={() =>{dispatch({type: 'ADD'})}}>+</button>
             <button onClick={() =>{dispatch({type: 'SUB'})}}>-</button>
            {/* <button onClick={() =>{setNumState(numState+1)}}>+</button>
            <p>{numState}</p>
            <button onClick={() =>{setNumState(numState-1)}}>-</button> */}
        </div>
    )
}

export default function UseReducer() {
  return (
      <div>
          <Child1/>
          <hr />
          <Child2/>
      </div>
  )
}

6. useCallback

useCallback Hook用于优化代码,可以让对应的函数只有在依赖发生变化时重新定义。
只要依赖没有发生变化,那么useCallback返回的永远都是同一个函数。
useCallback底层是利用useMemo实现的。
    // 实现原理
    function useCallback(fn,arr){
        return useMemo(() =>{
            return fn
        },arr)
    }
useCallback和useMemo的区别:
    1. useCallback返回的永远都是一个函数
    2. useMemo返回的是return返回的内容
    
// jsx文件
import React, { memo, useCallback, useState } from 'react';

function Child1(props) {
  console.log('Child1组件',props);
  return (
    <div>
      <p>Child1组件</p>
      <button onClick={() =>{props.add()}}>+</button>
    </div>
  )
}

function Child2(props) {
  console.log('Child2组件',props);
  return (
    <div>
      <p>Child2组件</p>
      <button onClick={() =>{props.min()}}>-</button>
    </div>
  )
}

// 组件优化(避免子组件不必要的重复渲染,只让组件内的数据发生改变才重新渲染)
const MemoChila1 = memo(Child1)
const MemoChild2 = memo(Child2)

export default function UseCallback() {
  const [numState,setNumState] = useState(10)
  const [countState,setCountState] = useState(20)


  function add() {
    setNumState(numState+1)
  }
  // 只有依赖发生变化才会重新渲染
  const min = useCallback(() =>{
    setCountState(countState-1)
  },[countState])
  console.log('UseCallback组件');
  return (
    <div>
      <MemoChila1 add={add}/>
      <hr />
      <MemoChild2 min={min}/>
      <hr />
      <p>UseCallback组件</p>
      <p>{numState}</p>
      <p>{countState}</p>
      {/* <button onClick={() =>{setNumState(numState+1)}}>+</button> */}
      {/* <button onClick={() =>{setCountState(countState-1)}}>-</button> */}
    </div>
  )
}

7. useMemo

useMemo Hook用于优化代码,可以让对应的函数只有在发生依赖变化时才返回新的值。
useMemo Hook对耗时耗性能函数进行优化。
useCallback和useMemo的区别:
    1. useCallback返回的永远都是一个函数
    2. useMemo返回的是return返回的内容
    3. useMemo
 
 // 场景一
 const add = useMemo(() =>{
      return () =>{
        setNumState(numState+1)
      }
  },[numState])   
  
  // 场景二
  // 这样写影响性能
  const user = {name: 'liu',age: 24} 
  
  // 优化性能
  const user = useMemo(() =>{
      return {name: 'liu',age: 24}
  },[])
  
  // 场景三 {定义一个耗时耗性能的函数(每次数据更新都会执行该函数)}
 function fn() {
        console.log('fn函数');
        let total = 0
        for (let i = 0; i < 100; i++) {
            total += i
        }
        return total
    }   

 // 优化性能(只有在组件被挂载时执行一次)
 const total = useMemo(() =>{
      return fn()
  },[])