react hooks的基础学习

223 阅读4分钟

react Hooks是官方提供的新特性

文章先讲useState, useEffect , useRef , useContext ,useReducer 的基本用法

后面会将useCallback,useMemo配合Memo对项目进行优化,以及使用自定义hooks来复用逻辑

当然还有一些不常用的hooks(useLayoutEffect,)

useState  (解决函数组件无状态的问题)
const [ data , setData ] = useState([])  
[]为初始值,data为声明的变量,setData修改值的函数

假设这里是值一个数组
setData((old)=>{
       const newVal = [...old] // 创建一个新的对象
       // 这里可以对该对象进行操作  这里必须返回一个新的对象,如果直接返回old,不会触发更新
       return newval   
 })
注意点:1.class组件的this.setState更新是state是合并, useState中setData是替换。
      2.setData()替换的对象不能是同一个,替换的意思是不同的对象(注意会有小坑)
      3.setData((oldData)=>[...oldData,obj]) 参数是函数时,函数的参数是旧值,返回的是新值


useEffect  (官方介绍是用来进行各种副作用的函数,相当于类组件的三个生命周期函数)

useEffect(() => {
  /* 这里进行各种操作
  网络请求,重新赋值,事件,dom操作都可以
  */ 
  return ()=> {}
  // 这里返回一个函数相当于WillUnmount(组件卸载时触发的周期函数)
},[data])

第一个函数是用来执行各种副作用的,函数的返回值
第二参数:
	1.不传,组件每次 render 之后 useEffect 都会调用,相当与DidMountDidUpdate
        2.[],代表DidMountWillUnmount 两个周期函数
        3.传入一个数组,其中包括变量,只有这些变量变动时,useEffect 才会执行
        
注意点:1.data可以是任意值,包括传值过来的数据,声明的变量,页面跳转传参
      2.useEffect 是在render之后生效执行的。(组件完成渲染之后在执行的)
      
useRef  (获取dom,保存某些状态,父触发子方法/拿子的数据)(修改useRef的值是不会触发组件更新)
const dataRef = useRef()  //创建useRef对象

<button ref={dataRef} />   //作用于dom就可以获取对应的dom,echarts初始化建议使用,使用传统的js原生获取dom会有一些bug

 
dataRef.current  // 获取dom   可以保存状态
dataRef.current 是可以直接修改的

父触发子方法/拿子的数据(useRef,useImperativeHandle)

子组件中:
import {useImperativeHandle} from 'react'

const Children = ({parentRef})=> { 
  		// parentRef是父组件的ref引用
  		useImperativeHandle(parentRef,()=> ({
                        // 向外暴露一个对象,其实包括changeVal方法,childrenData属性 
                            changeVal:(参数)=>{
            		// 这里可以进行各种操作
                        // setData()
                        },
        		childrenData:'123'
      	
              }))
}

父组件中
import {useRef} from 'react'

const Parent = () => {
		const parentRef = useRef()  // 创建ref引用
     
    // 定义一个用来触发子组件方法的函数
    const updata = () => {
      // parent.curren 可以拿到子组件的方法或者数据
    	parent.current.changeVal(参数)  // 调用子组件的方法
      parnet.current.childrenData    // 123
    }
    return (
    <div>	
      <Children parentRef={parentRef} />  //这里不要用ref绑定 
     </div>
    )

useContext(实现组件的跨级传值但不能修改传入的值)   useReducer(生成数据以及修改数据的函数)
这两个配合使用可以达到react-redux的效果
useContext用法
 // 引入生成传值的组件
import { createContext } from 'react'
 // 调用生成传值的组件的函数
export const ParentState = createContext()   

// 用传值的组件包裹需要共享状态的组件,无论被包裹的组件嵌套多深,都可以拿到
// state就是共享的状态数据   可以是函数,对象
<ParentState.Provide value={ state } >
      <组件>
 </ParentState.Provide >

//  在被包裹的组件中,拿到传过来的值

import {useContext} from 'react'
import {parentState} from '父组件'

const state = useContext(parentState)


useReducer  用法
import {useReducer}  from 'react'

// data是初始值,箭头函数是用来写修改数据的业务逻辑  
// state是最新的数据,dispatch就是修改data的箭头函数
const [state,dispatch] = useReducer((oldState,action)=>{                                                // oldState是旧数据,action是调用函数时传的参数      
         switch (action.type) {
         case 'add':
         return oldState + action.num
         default:
         throw new error('Unexpected action')
        }
         
},data)
	// 触发dispatch函数
  <button onClick={dispatch({type:'add',num:3})}>



项目中两者结合可以达到全局状态管理的效果 利用useReducer生成数据以及修改数据的函数.
useContext将数据和函数全局共享  从而达到全局都可以修改这些数据
用法和redux很相似(用过的应该都知道)

以下是项目中对全局状态管理封装的store.js   向外暴露函数  调用即可拿到共享的数据以及函数   
                   
import React, { useReducer, useContext } from "react";
const stateStorage = sessionStorage.getItem("state");  // 从本地存储从获取值

// 初始化要传入的状态值
export const initialState = stateStorage
  ? JSON.parse(stateStorage)
  : {
    panes: [{ title: "首页", path: "/Index", key: "1" }], // tabs标签
    activeKey: "1", // tabs标签当前高亮
    position: [], // tabs标签栏左右点击按钮
    userInfo: {
      audit_acc: [],
      resp_acc: [],
      user_id: '',
      zzjg: {
        layer: null,
        prctr: null,
        prctr_name: null,
      },
    }, // 用户信息
   
  };
  // 修改状态的函数
const reducer = (state, action) => {
  switch (action.type) {
    case "PANES_":
      return Object.assign({}, state, { panes: action.panes });
    case "ACTIVEKEY_":
      return Object.assign({}, state, { activeKey: action.activeKey });
    case "POSITION_":
      return Object.assign({}, state, { position: action.position });
    default:
      throw new Error("Unexpected action");
  }
};
// 生成传值的组件
const SupportContext = React.createContext();

 // 封装组件来达到传值,
export const SupportProvider = ({ children }) => {
// contextValue是useReducer函数生成的[state,dispatch]作为状态值共享给所有组件
  const contextValue = useReducer(
    reducer,
    JSON.parse(JSON.stringify(initialState))
  );
  return (
    <SupportContext.Provider value={contextValue}>
      {children}
    </SupportContext.Provider>
  );
};

//  暴露拿到状态的函数
const useSupportReducer = () => {
  const contextValue = useContext(SupportContext);
  return contextValue;
};

export default useSupportReducer;

其他组件中使用
import useSupportReducer from '@/store.js'
const [store, dispatch] = useSupportReducer()

// store共享给组件的状态值
// dispatch 是修改用来状态值的函数   
   dispatch({
             type: 'PANES_',
             panes:panes,
             })