React钩子

时间:2022-12-20 21:03:55

1.项目导入react

import * as React from 'react';

2.使用对应各种钩子

目前项目中常用的有:
useState

useEffect

useRef

useReducer

useContext

useMemo

我一般将其一起引用(根据个人需求引入)

import React, {
  forwardRef,
  useContext,
  memo,
  useEffect,
  useState,
  useImperativeHandle
} from 'react';

1.useState

首先进行声明

const [bizTypeValue, setBizTypeValue] = useState('init');

其中第一个为使用的定义值,第一个为对值做赋值使用的函数,后续的useState括号中间为此值的初始化值,可以定义为字符,数组,对象都可以

赋值

setBizTypeValue("新值");

当声明的值进行变化后整改页面也会进行刷新,但是由于react的diff算法的原因只是引用该值的组件进行重新渲染,不过我们把这个值传给一个组件函数时候,值变化后就需要渲染整个组件函数,非常耗费资源,这个时候就需要加上memo到组件的导出声明处

export default memo(BasicInformation);

这个时候就只会更新该组件内部的引用改组件的值了

2.useEffect

常用的两种情况
1.进行组件初始化时进行赋值
2.当需要对某个值进行监控时并在改变后进行方法的执行

初始化使用

 React.useEffect(() => {
    initialization()
  }, []);

  const initialization = async () => {
    //初始化事件
  }

值监控(当bizTypeValue发生改变的时候触发)

React.useEffect(() => {
    '执行方法'
  }, [bizTypeValue]);

注意: 当在方法体执行useState的set方法时,值的结果是不能被正确打印的,因为钩子函数都是异步的,如

React.useEffect(() => {
    setBizTypeValue('新值')
    consloe.log(bizTypeValue)
  }, [bizTypeValue]);

3.useRef

由于现在公司基本都是用react的函数式编程,而ref是不能直接定义到函数式组件中的,这个时候就需要使用forwardRef

首先进行定义

const baseRef = useRef()

组件使用

<BaseInformation ref={baseRef} />

函数式组件定义使用

const BasicInformation = forwardRef((props, ref) => {}

我们在构建一个页面的时候会经常遇到父组件给子组件或者是子传父等常见的值传递场景,如果学过vue我们通常使用evenbus来解决这个问题,比较复杂的就是用vuex去解决,而react中,我们使用就是props来进行父传子,ref进行子传父的,而复杂的通常使用useContext和UseReducer配合使用解决

父传子
入值 

const  Index = () => {
    const [bizTypeValue, setBizTypeValue] = useState('init');
    return (
		<BaseInformation bizTypeValue={bizTypeValue} />
	)
}

取值

const BaseInformation = (props) => {
	const {bizTypeValue} = props
	console.log(bizTypeValue)
}

这个时候就会打印出 ‘init’ 的字符

子传父

入值

const  Index = () => {
    const baseRef = useRef()
    return (
		<BaseInformation ref={baseRef} />	)
}

取值

const BasicInformation = forwardRef((props, ref) => {
	return (
		<button ref={ref}>点击</button>
	)
}

我们就可以从父组件取到对应的button的全部信息了

不过有时候我们需要读取多个组件或者需要多个对象怎么办,我们可以将我们需要的值进行打包然后整个传给ref就可以了

  const getValues = () => {
    let data;
    field.validate((errors, values) => {
      if (!errors) {
        data = { ...values, serviceType };
      } else {
        data = false;
      }
    });
    return data;
  };

 //react方法
  useImperativeHandle(
    ref,
    () => ({
      getValues: getValues
    }),
    [getValues]
  );

上面是将form表单对像传过去了,当然我们也可以在getValues函数中返回更多参数
后续我们需要在父组件中使用ref对象时

const result = await baseRef.current.getValues()

4.useReducer useContext

这次对两个钩子一起介绍,一般也是一起进行使用的

useContext: 父组件下的所有子组件(包括子子组件)都可以使用被传输的值,不需要通过props一层层的往下传

useReducer: useReducer 是 useState 的替代方案,useState 能做到的事,它都能做到,甚至做得更好。useReducer 某种程度上解耦了操作逻辑(action)和后续的行为(一般是 UI 的更新),虽然代码量变多了,但是看起来更加整洁,并且配合useContext实现值的多层传递,实现各个组件间的值互通

首先进行定义


在父组件中进行定义

//初始化
const initialState = {
  base: {},
};
//定义reducer方法
function reducer(state, action) {
  switch (action.type) {
    case 'set_base':
      return {
        ...state,
        base: action.base
      };

    case 'reset':
      return init(action.payload);
    default:
      throw new Error();
  }
}


const  Index = () => {
	//定义参数 使用useReducer
    const [state, dispatch] = useReducer(reducer, initialState);
    export const InspecTemplates = useContext(item => item);
	export const InspecTemplatesState = useContext({});
    const baseRef = useRef()
    return (
    //传输一个对象
     <TemplatesState.Provider value={{ state }}>
     //传输一个方法
      <Templates.Provider value={{ dispatch }}>
		<BaseInformation ref={baseRef} />
	  </TemplatesState>
	</Templates>	
		)
}

使用

  const BasicInformation = forwardRef((props, ref) => {
  
    const [bizValue, setBizValue] = useState({text:'dispatch'});
  	//取值
    const { dispatch } = useContext(InspecTemplates);
 	const { state } = useContext(InspecTemplatesState);
 	//我们可以从任意一个层中取得base对象
	const { base } = state;
	
	//当bizValue发生改变后将bizValue赋值给base
	React.useEffect(() => {
		dispatch({ type: 'set_base', base: bizValue });
	}, [bizValue]);
	
	return (
		<button ref={ref}>点击</button>
	)
}

上面可以看出,当我们使用useContext和useReducer的联合使用从而达到值在多个组件层级中相互传递,达到和vueX差不多的效果

5.useMemo

我们可以将useEffect的精细版本,当indicatorSelect进行赋值后并没有发生改变后,useMemo会将上次的值直接返回,有点缓存感觉,当然也可以如上面介绍的,对组件函数进行使用,减少函数组件中组件的更新,从而到达减少系统的开销

 const indicatorSelectData = useMemo(() => {
    if (indicatorSelect?.length > 0) {
      return indicatorSelect.map((item) => {
        return {
          ...item,
          label: item.indicatorName,
          value: item.indicatorCode
        };
      });
    }
  }, [indicatorSelect]);