React Hooks 知识点整理

Hook 是 React 16.8 的新增特性。它可以让你在不编写 class 的情况下使用 state 以及其他的 React 特性。
————可以说之前我们用 Class 声明组件的方式会被淘汰掉

React Hooks 知识点整理_第1张图片

1. useState:

1. 使用方法:
// 1. 引用 useState 
import React, { useState } from 'react';
// 2. 声明一个 state(自定义)的 state 变量
const [state, setState] = useState(initialState); // initialState 为初始参数 参数可以是字符串、对象甚至是函数
// 3. 更新 state
setState(newState);

注意事项:
  1. 不支持局部更新:
    参数 initialState 若是对象,不可以局部更新,同理 useReducer 也不会局部更新参数,我们可以用 …user 来拷贝之前的属性,在局部覆盖来实现局部更新,具体操作如下
  2. 地址要变:
    setState(newState) 如果 newState 内存地址不变,那么 React 就认为数据没有变化
  3. 参数可以是函数
    useState、setState 都可接受函数
2. 用途:
	更新状态
3. 示例:
import React, { useState } from "react";
import "./styles.css";

function App() {
  const [user, setUser] = useState({ name: "Lokka", age: 18 });
  const onClick = () => {
    setUser({
      ...user,
      name: "XiaoMing"
    });
  };
  return (
    <div className="App">
      <h1>{user.name}</h1>
      <h2>{user.age}</h2>
      <button onClick={onClick}>Click</button>
    </div>
  );
}

export default App;

2. useEffect:

useEffect 的作用主要是用来解决函数组件如何像类组件一样使用生命周期钩子的问题,在 render 后执行。

1. 使用方法:
// 1. 引用 useEffect
import React, { useEffect} from 'react';
// 2. 创建 useEffect 函数
useEffect(() => {


  return () => {
    // 清除函数 组件卸载时需要清除 effect 创建的诸如订阅或计时器 ID 等资源。要实现这一点,useEffect 函数需返回一个清除函数
  };	
},[initialState]); // [initialState] 为 useEffect 第二个参数可以没有,只有当 initialState 改变后会重新调用,也可以写 [],那么就会执行一次
2. 用途:
  1. 作为 componentDidMount 使用,[ ] 作第二个参数
  2. 作为 componentDidUpdate 使用,可指定依赖
  3. 作为 componentWillUnmount 使用,通过 return
  4. 以上三种用途可同时存在
3. 示例:
import React, { useState, useEffect } from "react";

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

  // 类似于 componentDidMount 和 componentDidUpdate:
  useEffect(() => {
    // 更新窗口标题用浏览器 API
    document.title = `You clicked ${count} times`;
  });

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>Click me</button>
    </div>
  );
}

export default App;

2.1 useLayoutEffect:

与 useEffect 用法相同,不过 useLayoutEffect 在 render 前就会执行,在浏览器绘制完之前就会执行,而 useEffect 在 render 后执行,能用到的场景不多,推荐使用 useEffect

3. useContext:

如果我们想在父子组件之间传值的话,可以使用 useContext。

1. 使用方法:
// 1. 引用 useContext
import React, { useContext } from 'react';

// 2. 在父组件创建 context

let ctx = createContext(参数);

// 3. 用 ctx.Provider 包裹子组件,value值为要传给子组件的值

<ctx.Provider value={data}>
  <Person />
</ctx.Provider>

// 4. 子组件接收父组件的值

const data = useContext(ctx);
  return (
    <>
      <h1>{data.name}</h1>
    </>
  );
2. 用途:
	父子组件传值
3. 示例:
import React, { useState, createContext, useContext } from "react";

import "./styles.css";

let ctx = createContext("lokka");
function App() {
  let [data, setData] = useState({
    name: "小明",
    age: 18
  });
  function change() {
    setData({
      ...data,
      name: "LOKKA"
    });
  }
  return (
    <div className="App">
      <ctx.Provider value={data}>
        <Person />
      </ctx.Provider>
      <button onClick={change}>改变</button>
    </div>
  );
}

function Person() {
  const data = useContext(ctx);
  return (
    <>
      <h1>{data.name}</h1>
    </>
  );
}

export default App;

4. useReducer:

useReducer 是用来代替 Redux 的,或者说,是一个加强版的 useState

1. 使用方法:
// 1. 引用 useReducer
import React, { useReducer} from 'react';

// 2. 创建 useReducer
const [state, dispatch] = useReducer(reducer, initialArg, init); // state 是返回的值 dispatch是返回的方法
// reducer 处理函数, initialArg 是初始值 , init 为函数参数,这样初始 state 将被设置为 init(initialArg)


// 3. 触发 dispatch 通过不同的 action.type 得到不同的返回值

dispatch({
type: "setname",
name: "lokka"
})

2. 用途:
	高级版的 useState,用来代替 Redux
3. 示例:
import React, { useReducer } from "react";

import "./styles.css";

const initial = {
  n: 0
};

const reducer = (state, action) => {
  switch (action.type) {
    case "add":
      return {
        n: state.n + action.number
      };
    case "multi":
      return {
        n: state.n * 2
      };
    default: {
      return state;
    }
  }
};

function App() {
  const [state, dispatch] = useReducer(reducer, initial);
  const { n } = state;
  const onClick = () => {
    dispatch({ type: "add", number: 1 });
  };
  const onClick2 = () => {
    dispatch({ type: "add", number: 2 });
  };
  return (
    <div className="App">
      <h1>n: {n}</h1>

      <button onClick={onClick}>+1</button>
      <button onClick={onClick2}>+2</button>
    </div>
  );
}

export default App;

5. useMemo:

useMemo 是用来性能优化,防止重复渲染

1. 使用方法:
const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);
2. 用途:
  1. 类似与 Vue 的计算属性 computed,useMemo 具有缓存,依赖([a, b])改变才重新渲染的功能,空数组 [] 代表无论什么情况下该函数都不会发生改变

  2. 跟它的小弟 useCallback 的唯一区别是:useMemo可以缓存所有对象,useCallback只能缓存函数。

和 useCallback 区别:
useCallback 不会执行第一个参数函数,而是将它返回给你,而 useMemo 会执行第一个函数,并且将函数执行结果返回给你。

和 useEffect 区别:
useEffect 没有返回值,并且是在render之后才执行的,而 useMemo 有返回值,并且是在页面渲染的时候进行的。

3. 示例:
useMemo:
import React, { useState, useMemo } from "react";

import "./styles.css";

function App() {
  let [count, setCount] = useState(0);
  let res = useMemo(() => count * 10, [count]);
  const onClick = () => {
    setCount(count + 1);
  };
  return (
    <div className="App">
      <h1>{res}</h1>

      <button onClick={onClick}>+1</button>
    </div>
  );
}

export default App;

5.1 useCallback

1. 使用方法:
useCallback(x => log(x), [m]) 等价于 useMemo(() => x => log(x), [m]);
2. 用途:

useCallback只缓存函数,不立即执行,直接返回函数

3. 示例:
useCallback:
import React, { useState, useCallback } from "react";

import "./styles.css";

function App() {
  let [count, setCount] = useState(0);
  let res = useCallback(() => count * 10, [count]);
  const onClick = () => {
    setCount(count + 1);
  };
  return (
    <div className="App">
      <h1>{res()}</h1>

      <button onClick={onClick}>+1</button>
    </div>
  );
}

export default App;

6. useRef:

useRef 用来生成对 DOM 对象的引用

1. 使用方法:
const refContainer = useRef(initialValue);

useRef 返回一个可变的 ref 对象,其 .current 属性被初始化为传入的参数(initialValue)。返回的 ref 对象在组件的整个生命周期内保持不变。

2. 用途:
  1. useRef 可以通过组件或者 DOM 的 ref 属性,访问组件或真实的 DOM 节点,重点是组件也是可以访问到的,从而可以对 组件 、DOM 进行一些操作,比如获取 input 值、监听事件等等。

  2. 当然 useRef 远比你想象中的功能更加强大,useRef 的功能有点像类属性,或者说您想要在组件中记录一些值,并且这些值在稍后可以更改。

3. 示例:
import React, { useState, useRef } from "react";

import "./styles.css";

function App() {
  let [val, setVal] = useState("p 初始值");
  const inputEl = useRef(null);
  const onButtonClick = () => {
    // `current` 指向已挂载到 DOM 上的文本输入元素
    setVal(inputEl.current.value);
  };
  return (
    <>
      <p>{val}</p>
      <input ref={inputEl} type="text" />
      <button onClick={onButtonClick}>Focus the input</button>
    </>
  );
}

export default App;

6.1 useImperativeHandle:

  1. 使用 ref 自定义暴露给父组件,这样父组件就可以获得子组件的属性或方法。
  2. useImperativeHandle 应当与 forwardRef 一起使用。
1. 使用方法:
useImperativeHandle(ref, createHandle, [deps])
2. 用途:
	获取子组件的方法或者属性
3. 示例:
import React, { useRef, useImperativeHandle, forwardRef } from "react";
function ChildInputComponent(props, ref) {
  const inputRef = useRef("子组件的LOKKA");
  useImperativeHandle(ref, () => inputRef.current);
  return <input type="text" name="child input" ref={inputRef} />;
}
const ChildInput = forwardRef(ChildInputComponent);
function App() {
  const inputRef = useRef(null);
  let focus = () => {
    inputRef.current.focus();
  };
  return (
    <div>
      子组件:
      <ChildInput ref={inputRef} />
      <br />
      父组件<button onClick={focus}>按钮</button>
    </div>
  );
}

export default App;

7. 自定义 HOOK:

和普通函数本质上没有区别,都是做一些函数的封装,方便使用

1. 使用方法:
  1. 自定义 hook ,必须以 use 开头
  2. 自定义 hook ,可以使用上面的 hook(useState, useEffect…)来封装
2. 用途:
	封装 hook 复用
3. 示例:

简易的计算器:

import React, { useReducer } from "react";
import "./styles.css";

const reducer = (init, action) => {
  switch (action.type) {
    case "add":
      return init + action.num;
    case "subtract":
      return init - action.num;
    case "multiply":
      return init * action.num;
    case "divide":
      return init / action.num;
    default: {
      return init;
    }
  }
};

const useCount = (countType, init, num) => {
  const [count, dispatch] = useReducer(reducer, init);
  const bingo = () => {
    dispatch({ type: countType, num: num });
  };
  return { count, bingo };
};

function App() {
  let { count, bingo } = useCount("subtract", 2, 2);
  return (
    <div className="App">
      <h1>{count}</h1>
      <button onClick={bingo}>Click</button>
    </div>
  );
}

export default App;

7.1 useDebugValue:

用来对自定义的 hook 进行调试,强调一下,这个方法使在自定义 hook 中用的,其他 hook 中无效

1. 使用方法:
useDebugValue(value)
2. 用途:
  1. useDebugValue 可用于在 React 开发者工具中显示自定义 hook 的标签。
  2. 标签上显示的是一个调试值,方便调试的时候参考。
3. 示例:
import React, { useReducer, useDebugValue } from "react";
import "./styles.css";

const reducer = (init, action) => {
  switch (action.type) {
    case "add":
      return init + action.num;
    case "subtract":
      return init - action.num;
    case "multiply":
      return init * action.num;
    case "divide":
      return init / action.num;
    default: {
      return init;
    }
  }
};

const useCount = (countType, init, num) => {
  const [count, dispatch] = useReducer(reducer, init);
  const bingo = () => {
    dispatch({ type: countType, num: num });
  };
  useDebugValue(count < 0 ? "不能出负数" : "没问题");
  return { count, bingo };
};

function App() {
  let { count, bingo } = useCount("subtract", 2, 2);
  return (
    <div className="App">
      <h1>{count}</h1>
      <button onClick={bingo}>Click</button>
    </div>
  );
}

export default App;

React Hooks 知识点整理_第2张图片

你可能感兴趣的:(REACT,react.js,javascript,前端)