其他分享
首页 > 其他分享> > ♣ React Hooks的使用

♣ React Hooks的使用

作者:互联网

React Hooks的使用

为什么需要Hook?

Hook 是 React 16.8 的新增特性,它可以让我们在不编写class的情况下使用state以及其他的React特性(比如生命周期)。

Class组件存在的问题

Hook的出现,可以解决上面提到的这些问题;

简单总结一下hooks: 它可以让我们在不编写class的情况下使用state以及其他的React特性;但是我们可以由此延伸出非常多的用法,来让我们前面所提到的问题得到解决;

Hook的使用场景:

useState解析

useState来自react,需要从react中导入,它是一个hook;

查看代码
import React, { useState } from 'react'

export default function ComplexHookState() {

  const [friends, setFrineds] = useState(["kobe", "lilei"]);
  const [students, setStudents] = useState([
    { id: 110, name: "why", age: 18 },
    { id: 111, name: "kobe", age: 30 },
    { id: 112, name: "lilei", age: 25 },
  ])

  function addFriend() {
    friends.push("hmm");
    setFrineds(friends);
  }

  function incrementAgeWithIndex(index) {
    const newStudents = [...students];
    newStudents[index].age += 1;
    setStudents(newStudents);
  }

  return (
    <div>
      <h2>好友列表:</h2>
      <ul>
        {
          friends.map((item, index) => {
            return <li key={index}>{item}</li>
          })
        }
      </ul>
      <button onClick={e => setFrineds([...friends, "tom"])}>添加朋友</button>
      {/* 错误的做法 */}
      <button onClick={addFriend}>添加朋友</button>

      <h2>学生列表</h2>
      <ul>
        {
          students.map((item, index) => {
            return (
              <li key={item.id}>
                <span>名字: {item.name} 年龄: {item.age}</span>
                <button onClick={e => incrementAgeWithIndex(index)}>age+1</button>
              </li>
            )
          })
        }
      </ul>
    </div>
  )
}

但是使用它们会有两个额外的规则:

State Hook的API就是 useState

认识Effect Hook

目前我们已经通过hook在函数式组件中定义state,那么类似于生命周期这些呢?

useEffect的解析:

在class组件的编写过程中,某些副作用的代码,我们需要在componentWillUnmount中进行清除:比如我们之前的事件总线或Redux中手动调用subscribe;都需要在componentWillUnmount有对应的取消订阅;Effect Hook通过什么方式来模拟componentWillUnmount呢?

useEffect传入的回调函数A本身可以有一个返回值,这个返回值是另外一个回调函数B:type EffectCallback = () => (void | (() => void | undefined));

为什么要在 effect 中返回一个函数? 这是 effect 可选的清除机制。每个 effect 都可以返回一个清除函数;如此可以将添加和移除订阅的逻辑放在一起;它们都属于 effect 的一部分;

查看代码
import React, { useEffect, useState } from 'react'

export default function EffectHookCancelDemo() {

  const [count, setCount] = useState(0);

  useEffect(() => {
    console.log("订阅一些事件");

    return () => {
      console.log("取消订阅事件")
    }
  }, []);

  return (
    <div>
      <h2>EffectHookCancelDemo</h2>
      <h2>{count}</h2>
      <button onClick={e => setCount(count + 1)}>+1</button>
    </div>
  )
}

使用多个Effect

Hook 允许我们按照代码的用途分离它们, 而不是像生命周期函数那样:React 将按照 effect 声明的顺序依次调用组件中的每一个 effect;

查看代码
import React, { useState, useEffect } from 'react'

export default function MultiEffectHookDemo() {
  const [count, setCount] = useState(0);
  const [isLogin, setIsLogin] = useState(true);

  useEffect(() => {
    console.log("修改DOM", count);
  }, [count]);

  useEffect(() => {
    console.log("订阅事件");
  }, []);

  useEffect(() => {
    console.log("网络请求");
  }, []);

  return (
    <div>
      <h2>MultiEffectHookDemo</h2>
      <h2>{count}</h2>
      <button onClick={e => setCount(count + 1)}>+1</button>
      <h2>{isLogin ? "coderwhy": "未登录"}</h2>
      <button onClick={e => setIsLogin(!isLogin)}>登录/注销</button>
    </div>
  )
}

Effect性能优化

默认情况下,useEffect的回调函数会在每次渲染时都重新执行,但是这会导致两个问题:

我们如何决定useEffect在什么时候应该执行和什么时候不应该执行呢?useEffect实际上有两个参数:

但是,如果一个函数我们不希望依赖任何的内容时,也可以传入一个空的数组 [],那么这里的两个回调函数分别对应的就是componentDidMount和componentWillUnmount生命周期函数了;

useContext的使用

在之前的开发中,我们要在组件中使用共享的Context有两种方式:

但是多个Context共享时的方式会存在大量的嵌套:Context Hook允许我们通过Hook来直接获取某个Context的值;

useReducer

很多人看到useReducer的第一反应应该是redux的某个替代品,其实并不是。

useReducer仅仅是useState的一种替代方案:

在某些场景下,如果state的处理逻辑比较复杂,我们可以通过useReducer来对其进行拆分;或者这次修改的state需要依赖之前的state时,也可以使用;

查看代码
import React, { useState, useReducer } from 'react';

import reducer from './reducer';

export default function Home() {
  // const [count, setCount] = useState(0);
  const [state, dispatch] = useReducer(reducer, {counter: 0});

  return (
    <div>
      <h2>Home当前计数: {state.counter}</h2>
      <button onClick={e => dispatch({type: "increment"})}>+1</button>
      <button onClick={e => dispatch({type: "decrement"})}>-1</button>
    </div>
  )
}
查看代码
import React, { useReducer } from 'react';

import reducer from './reducer';

export default function Profile() {
  // const [count, setCount] = useState(0);
  const [state, dispatch] = useReducer(reducer, { counter: 0 });

  return (
    <div>
      <h2>Profile当前计数: {state.counter}</h2>
      <button onClick={e => dispatch({ type: "increment" })}>+1</button>
      <button onClick={e => dispatch({ type: "decrement" })}>-1</button>
    </div>
  )
}
查看代码
export default function reducer(state, action) {
  switch(action.type) {
    case "increment":
      return {...state, counter: state.counter + 1};
    case "decrement":
      return {...state, counter: state.counter - 1};
    default:
      return state;
  }
}

数据是不会共享的,它们只是使用了相同的counterReducer的函数而已。所以,useReducer只是useState的一种替代品,并不能替代Redux。

useCallback

useCallback实际的目的是为了进行性能的优化。

如何进行性能的优化呢?

案例

通常使用useCallback的目的是不希望子组件进行多次渲染,并不是为了函数进行缓存;

查看代码
import React, { useState, useCallback, useMemo } from 'react'
//不能进行的性能优化
export default function CallbackHookDemo01() {
  const [count, setCount] = useState(0);

  const increment1 = () => {
    console.log("执行increment1函数");
    setCount(count + 1);
  }

  const increment2 = useCallback(() => {
    console.log("执行increment2函数");
    setCount(count + 1);
  }, [count]);

  const increment3 = useMemo(() => {
    return () => {
      console.log("执行increment2函数");
      setCount(count + 1);
    }
  }, [count]);

  return (
    <div>
      <h2>CallbackHookDemo01: {count}</h2>
      <button onClick={increment1}>+1</button>
      <button onClick={increment2}>+1</button>
    </div>
  )
}
查看代码
import React, {useState, useCallback, memo} from 'react';

/**
 * useCallback在什么时候使用?
 * 场景: 在将一个组件中的函数, 传递给子元素进行回调使用时, 使用useCallback对函数进行处理.
 */

const HYButton = memo((props) => {
  console.log("HYButton重新渲染: " + props.title);
  return <button onClick={props.increment}>HYButton +1</button>
});

export default function CallbackHookDemo02() {
  console.log("CallbackHookDemo02重新渲染");

  const [count, setCount] = useState(0);
  const [show, setShow] = useState(true);

  const increment1 = () => {
    console.log("执行increment1函数");
    setCount(count + 1);
  }

  const increment2 = useCallback(() => {
    console.log("执行increment2函数");
    setCount(count + 1);
  }, [count]);

  return (
    <div>
      <h2>CallbackHookDemo01: {count}</h2>
      {/* <button onClick={increment1}>+1</button>
      <button onClick={increment2}>+1</button> */}
      <HYButton title="btn1" increment={increment1}/>
      <HYButton title="btn2" increment={increment2}/>

      <button onClick={e => setShow(!show)}>show切换</button>
    </div>
  )
}

useMemo

useMemo实际的目的也是为了进行性能的优化。如何进行性能的优化呢?

案例:

查看代码
import React, {useState, useMemo} from 'react';

function calcNumber(count) {
  console.log("calcNumber重新计算");
  let total = 0;
  for (let i = 1; i <= count; i++) {
    total += i;
  }
  return total;
}

export default function MemoHookDemo01() {
  const [count, setCount] = useState(10);
  const [show, setShow] = useState(true);

  // const total = calcNumber(count);
  const total = useMemo(() => {
    return calcNumber(count);
  }, [count]);

  return (
    <div>
      <h2>计算数字的和: {total}</h2>
      <button onClick={e => setCount(count + 1)}>+1</button>
      <button onClick={e => setShow(!show)}>show切换</button>
    </div>
  )
}
查看代码
import React, { useState, memo, useMemo } from 'react';

const HYInfo = memo((props) => {
  console.log("HYInfo重新渲染");
  return <h2>名字: {props.info.name} 年龄: {props.info.age}</h2>
});

export default function MemoHookDemo02() {
  console.log("MemoHookDemo02重新渲染");
  const [show, setShow] = useState(true);

  // const info = { name: "why", age: 18 };
  const info = useMemo(() => {
    return { name: "why", age: 18 };
  }, []);

  return (
    <div>
      <HYInfo info={info} />
      <button onClick={e => setShow(!show)}>show切换</button>
    </div>
  )
}

 

标签:count,const,函数,Hooks,React,state,useState,使用,组件
来源: https://www.cnblogs.com/sunflower-js/p/15863599.html