react hook的基本使用大杂烩

2021-08-12  本文已影响0人  虎牙工务员刘波

react hook的出现标志着无状态组件的消失。

从百草园到三味书屋,
从class类组件杀到纯函数组件....

主要从这几个常用hook入手:
useState、useEffect、 useContext、useRef、 useImperativeHandle、memo、useMemo、useCallback
分别例举应用场景。

1、useState

和class的state差不多。

最简单应用:

export default function IndexPage() {

  let test = 1;
  const [data, setData] = useState(0);   //直接赋值
  const [data2, setData2] = useState(() => {   //可以是一个函数返回值
    return test + 1;
  });
  
  return (
    <div>
      <Button onClick={() => setData(1)}>测试{data}</Button>
      <Button onClick={() => setData2(2)}>测试{data2}</Button>
    </div>
  );
}

如果在某些情况不受外界影响,想拿到前一次的值:

export default function IndexPage() {

  let test = 1;
  const [data, setData] = useState(0);   //直接赋值
  const [data2, setData2] = useState(() => {   //可以是一个函数返回值
    return test + 1;
  });

  const dosome = () => {
    setData((prevState => prevState + 1));  //通过这种方式取得最新的上一次值
  };

  return (
    <div>
      <Button onClick={() => dosome()}>测试{data}</Button>
      <Button onClick={() => setData2(2)}>测试{data2}</Button>
    </div>
  );
}

2、useEffect

类似 React class 的生命周期函数componentDidMount,componentDidUpdate 和 componentWillUnmount 这三个函数的组合。

做请求:

export default function IndexPage() {

  const [params, setParams] = useState({ page: 1, pageSize: 10 });  

  useEffect(() => {
    fetch('xxx/xxx/xxx', params).then(r => console.log(r));
  }, [params]);

  return (
    <div>
      <Button onClick={() => setParams({ page: 2, pageSize: 10 })}>请求</Button>
    </div>
  );
}

useEffect:只能在初始渲染和DOM更新后触发
它的第二个参数是一个数组,即依赖,每依赖变动时候,都会触发useEffect内的方法。如果数组为空,那么只会在初始渲染运行一次。
比如当params1或者params2或者params3,任意一个改变的时候就会打印输出1:

  useEffect(() => {
    console.log(1);
  }, [params1, params2, params3]);

假设有多个不同请求时候,需要写多个对应的请求依赖,对应依赖参数变化后做出请求:

export default function IndexPage() {

  const [params, setParams] = useState({ page: 1, pageSize: 10 });
  const [params2, setParams2] = useState({ page: 1, pageSize: 10 });

  useEffect(() => {
    fetch1('xxx/xxx/xxx', params).then(r => console.log(r));
  }, [params]);

  useEffect(() => {
    fetch2('xxx/xxx/xxx', params2).then(r => console.log(r));
  }, [params2]);
  
  return (
    <div>
      <Button onClick={() => setParams({ page: 2, pageSize: 10 })}>请求1</Button>
      <Button onClick={() => setParams2({ page: 1, pageSize: 5 })}>请求2</Button>
    </div>
  );
}

当点击请求1,修改params参数变化,触发第一个useEffect;点击请求2,修改params2参数变化,触发第二个useEffect,发起请求以此类推。
卸载时候,如清除定时器:

export default function IndexPage() {

  const [params, setParams] = useState({ page: 1, pageSize: 10 });

  useEffect(() => {
    let time = setInterval(() => {
      console.log(111);
    }, 1000);
    return () => {    //这里return一个函数,表示卸载时候运行的方法
      clearInterval(time);
    };
  }, [params]);

  return (
    <div>
      <Button onClick={() => setParams({ page: 2, pageSize: 10 })}>请求1</Button>
    </div>
  );
}

3、useContext

穿透传递上下文数据或者方法,在父组件创建一个上下文,再通过Provider传递给子组件,只需要包裹住,不管子组件多少层级都可以随意用到。

-------父组件:

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

export const TestContext = createContext('默认参数');

export default function IndexPage() {

  const [params, setParams] = useState('');

  return (
    <TestContext.Provider value={params}>
      <Button onClick={() => setParams('参数2')}>点击</Button>
      <div>父组件</div>
      <Child />
    </TestContext.Provider>
  );
}

-------子组件:这里子组件引用孙组件

import React from 'react';
import ChildTwo from '../ChildTwo';

function Index() {

  return (
    <div>
      <div>
        孩子组件
      </div>
      <ChildTwo />
    </div>
  );
}

export default Index;

-------孙组件:最终取值

import React, { Component, useContext } from 'react';
import { TestContext } from '../index';

function Index() {

  let getContext = useContext(TestContext);

  return (
    <div>
      孙子组件: {getContext}
    </div>
  );
}

export default Index;
点击前:
点击后:

4、useImperativeHandle(需要配合forwardRef、useRef)

作用:hook中父组件可以直接调用子组件的方法

正常下,我们编写代码,都是把父组件方法通过props传递给子组件运行,某些情况下,需要把子组件方法传递给父组件,hook组件需要这样写,父组件使用useRef并且赋给子组件:
请注意:hooks中要使用useRef,而class组件要使用createRef。
-----父组件

import React, { useRef } from 'react';
import { Button } from 'antd';
import Child from './Child';

export default function IndexPage() {

  const childRef = useRef();

  const clickChild = () => {
    childRef.current.change();
  };

  return (
    <div>
      <Button onClick={() => clickChild()}>点击</Button>
      <div>父组件</div>
      <Child ref={childRef} />
    </div>
  );
}

------子组件
useImperativeHandle的第一个参数接收到的ref,第二个是一个函数,函数需要返回传递给父组件的方法,子组件用forwardRef包裹,类似高阶函数用法。

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

function Index(props, ref) {

  const [data, setData] = useState(1);

  const test = () => {
    setData(data + 1);
  };

  useImperativeHandle(ref, () => ({    
    change: () => test(),
  }));

  return (
    <div>
      <div>
        孩子组件:{data}
      </div>
    </div>
  );
}

export default forwardRef(Index);

每次点击按钮数值加1


5、memo

效果等同与class组件的PureComponent,或者是shouldCompomentUpdate,只能进行浅层比较,既简单数据类型如:bool、string、number、undefind、null
作用:避免组件做不必要的更新(减少频繁更新次数)

使用非常简单,用包裹于子组件。一般情况下也是用来控制,当父组件传给子组件的值变化时候,子组件避免做不必要频繁更新次数。

import React, { memo } from 'react';

function Index() {

  return (
    <div>

    </div>
  );
}

export default memo(Index);

应用场景:
https://www.jianshu.com/p/822e061d960f

上一篇下一篇

猜你喜欢

热点阅读