• React Hooks解析


    1. react使用hook的意义

    Hook 是 React 16.8 的新增特性,它可以让我们在不编写class的情况下使用state以及其他的React特性(比如生命周期)。
    class组件与函数式组件:
    • class组件可以定义自己的state,用来保存组件自己内部的状态,函数式组件不可以,因为函数每次调用都会产生新的临时变量;
    • class组件有 自己的生命周期 ,我们可以在 对应的生命周期中完成自己的逻辑, 比如在componentDidMount中发送网络请求,并且该生命周期函数只会执行一次,如果在函数中发送网络请求,意味着每次重新渲染都会重新发送一次网络请求;
    • class组件可以 在状态改变时只会重新执行render函数 以及 我们希望重新调用的生命周期函数componentDidUpdate 等,函数式组件在重新渲染时,整个函数都会被执行,似乎没有什么地方可以只让它们调用一次;

    hook的出现就是为了解决函数式组件中实现class组件的很多特性,它可以让我们在不编写class的情况下使用state以及其他的React特性;

    2. useState Hook解析

    useState来自react,需要从react中导入,它是一个hook
    • 参数:初始化值,如果不设置为undefined;
    • 返回值:数组,包含两个元素,元素一: 当前状态的值(第一调用为初始化值) ,元素二: 设置状态值的函数

    注意:

    • 只能在函数最外层调用 Hook。不要在循环、条件判断或者子函数中调用;
    • 只能在 React 的函数组件中调用 Hook。不要在其他 JavaScript 函数中调用;
    1. import { memo, useState } from "react";
    2. // 普通的函数, 里面不能使用hooks
    3. // 在自定义的hooks中, 可以使用react提供的其他hooks: 必须使用use开头
    4. // function useFoo() {
    5. // const [ message ] = useState("Hello World")
    6. // return message
    7. // }
    8. function CounterHook(props) {
    9. const [counter, setCounter] = useState(0)
    10. const [name] = useState("why")
    11. console.log(name)
    12. // const message = useFoo()
    13. return (
    14. <div>
    15. <h2>当前计数: {counter}h2>
    16. <button onClick={e => setCounter(counter+1)}>+1button>
    17. <button onClick={e => setCounter(counter-1)}>-1button>
    18. div>
    19. )
    20. }

    3. useEffect Hook解析

    • Effect Hook 可以让你来完成一些类似于class中生命周期的功能;
    • 类似于 网络请求、手动更新DOM、一些事件的监听 ,都是 React更新DOM的一些副作用;
    • 对于完成这些功能的Hook被称之为 Effect Hook;

    useEffect的解析:

    • 通过useEffect的Hook,可以告诉React需要在渲染后执行某些操作;
    • useEffect 要求我们传入一个回调函数 ,在React 执行完更新DOM操作之后 ,就 会回调这个函数;
    • 默认情况下, 无论是第一次渲染之后 ,还是每次更新之后,都会 执行这个 回调函数;

    清除Effect:

    在class组件的编写过程中,某些副作用的代码,我们需要在componentWillUnmount中进行清除;
    • 比如我们之前的事件总线或Redux中手动调用subscribe;
    • 都需要在 componentWillUnmount有对应的取消订阅;
    useEffect传入的 回调函数A 本身可以有一个返回值,这个返回值是另外一个 回调函数B 这是 effect 可选的清除机制 每个 effect 都可以返回一个清除函数 如此可以 将添加和移除订阅的逻辑放在一起 都属于 effect 的一部分;
    1. // 负责告知react, 在执行完当前组件渲染之后要执行的副作用代码
    2. useEffect(() => {
    3. // 1.监听事件
    4. // const unubscribe = store.subscribe(() => {
    5. // })
    6. // function foo() {
    7. // }
    8. // 返回值: 回调函数 => 组件被重新渲染或者组件卸载的时候执行
    9. return () => {
    10. }
    11. })
    默认情况下,useEffect的回调函数会在每次渲染时都重新执行,但是这会导致两个问题:
    • 某些代码我们只是 希望执行一次即可 ,类似于componentDidMount和componentWillUnmount中完成的事情;(比如网络请求、订阅和取消订阅);
    • 多次执行也会导致一定的性能问题;

    useEffect的解决方式:

    useEffect实际上有两个参数,参数一: 执行的回调函数, 参数二:该 useEffect在哪些state发生变化时,才重新执行
    如果一个函数我们不希望依赖任何的内容时,也可以传入一个空的数组 【】;
    1. useEffect(() => {
    2. console.log("修改title:", count)
    3. }, [count])
    4. useEffect(() => {
    5. console.log("监听redux中的数据")
    6. return () => {}
    7. }, [])
    8. useEffect(() => {
    9. console.log("监听eventBus的why事件")
    10. return () => {}
    11. }, [])
    12. useEffect(() => {
    13. console.log("发送网络请求, 从服务器获取数据")
    14. return () => {
    15. console.log("会在组件被卸载时, 才会执行一次")
    16. }
    17. }, [])

     4. useContext Hook解析

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

    • 类组件可以通过 类名.contextType = MyContext方式,在类中获取context;
    • 多个Context或者在函数式组件中通过 MyContext.Consumer 方式共享context;
    但是多个Context共享时的方式会存在大量的嵌套:
    • Context Hook允许我们通过Hook来直接获取某个Context的值

    contxt.js

    1. import { createContext } from "react";
    2. const UserContext = createContext()
    3. const ThemeContext = createContext()
    4. export {
    5. UserContext,
    6. ThemeContext
    7. }

    App.jsx

    1. import React, { memo, useContext } from 'react'
    2. import { UserContext, ThemeContext } from "./context"
    3. const App = memo(() => {
    4. // 使用Context
    5. const user = useContext(UserContext)
    6. const theme = useContext(ThemeContext)
    7. return (
    8. <div>
    9. <h2>User: {user.name}-{user.level}h2>
    10. <h2 style={{color: theme.color, fontSize: theme.size}}>Themeh2>
    11. div>
    12. )
    13. })
    14. export default App

    5. useReducer Hook解析

    useReducer仅仅是useState的一种替代方案:
    • 在某些场景下,如果state的处理逻辑比较复杂,我们可以通过useReducer来对其进行拆分;
    • 或者这次修改的state需要依赖之前的state时,也可以使用;
    1. import React, { memo, useReducer } from 'react'
    2. function reducer(state, action) {
    3. switch(action.type) {
    4. case "increment":
    5. return { ...state, counter: state.counter + 1 }
    6. case "decrement":
    7. return { ...state, counter: state.counter - 1 }
    8. case "add_number":
    9. return { ...state, counter: state.counter + action.num }
    10. case "sub_number":
    11. return { ...state, counter: state.counter - action.num }
    12. default:
    13. return state
    14. }
    15. }
    16. const App = memo(() => {
    17. const [state, dispatch] = useReducer(reducer, { counter: 0, friends: [], user: {} })
    18. return (
    19. <div>
    20. <h2>当前计数: {state.counter}h2>
    21. <button onClick={e => dispatch({type: "increment"})}>+1button>
    22. <button onClick={e => dispatch({type: "decrement"})}>-1button>
    23. <button onClick={e => dispatch({type: "add_number", num: 5})}>+5button>
    24. <button onClick={e => dispatch({type: "sub_number", num: 5})}>-5button>
    25. <button onClick={e => dispatch({type: "add_number", num: 100})}>+100button>
    26. div>
    27. )
    28. })
    29. export default App
    数据是不会共享的,它们只是使用了相同的counterReducer的函数而已,所以,useReducer只是useState的一种替代品,并不能替代Redux。

    6. useRef Hook解析

    useRef返回一个ref对象,返回的ref对象在组件的 整个生命周期保持不 变。
    最常用的ref是两种用法:
    • 用法一:引入DOM(或者组件,但是需要是class组件)元素;
    • 用法二:保存一个数据,这个对象在整个生命周期中可以保存不变;
    1. import React, { memo, useRef } from 'react'
    2. const App = memo(() => {
    3. const titleRef = useRef()
    4. const inputRef = useRef()
    5. function showTitleDom() {
    6. console.log(titleRef.current)
    7. inputRef.current.focus()
    8. }
    9. return (
    10. <div>
    11. <h2 ref={titleRef}>Hello Worldh2>
    12. <input type="text" ref={inputRef} />
    13. <button onClick={showTitleDom}>查看title的dombutton>
    14. div>
    15. )
    16. })
    17. export default App
  • 相关阅读:
    配置静态IP地址(centos和ubuntu)
    K8S DiskPressure造成pod被驱逐——筑梦之路
    R语言计算data.table分组变量下每个分组的计数
    轨迹规划 | 图解路径跟踪PID算法(附ROS C++/Python/Matlab仿真)
    【Linux】权限
    一键解决Win10 LTSC 2021官方镜像存在的问题
    树莓派快速上手-远程调试图形界面
    box-shadow的使用
    《CTFshow - Web入门》03. Web 21~30
    使用 Qt for Android 获取并利用手机传感器数据(1)开发环境省心搭建
  • 原文地址:https://blog.csdn.net/weixin_47342624/article/details/134078052