【 React 】Hook 的那些事!

it2025-02-07  8

1、Hook 是什么

官方介绍:Hook 是 React 16.8 的新增特性。它可以让你在不编写 class 的情况下使用 state 以及其他的 React 特性。

2、Hook 的Api

1、useState 设置类组件中的state import React, { useState } from "react"; // useState: 可以在函数式组件中声明和修改状态 //函数式组件 function App() { //使用hook来定义state //获得state,和修改state的函数。 const [value, setValue] = useState("123"); 如果初始值比较复杂,可以用一个函数包裹,返回一个复杂对象。 const [userInfo, setUserInfo] = useState(getUserInfo); //如果需要定义多个状态,就调用多次useState return ( <div> <p>value: {value}</p> <input type="text" value={value} onChange={onChangeAction} /> <input type="text" value={value} onChange={onChangeAction()} /> // 这里加不加括号结果 都是一样的。应该在内部做了判断吧。 </div> ) // 输入框的修改事件 const onChangeAction = (ev) => { //调用上面定义的修改函数,要返回一个新的state,保证state的属性是不可变量。 setValue(ev.target.value); }; const getUserInfo = ()=>{ return { a:1, b:2 } } } export default App 2、useEffect 用来模拟 类组件中的各种生命周期钩子函数 //解构出`effect` // useEffect: 需要有一组依赖的state,如果依赖的state发生变化, 那么回调就会执行。 import React, { useState, useEffect } from "react"; ... //下面是函数组件内部代码 const [value, setValue] = useState("123"); // effect // 只要组件的所有state/props发生变化就执行。以及初始化也会执行 useEffect(()=>{ console.log('1 useEffect run.......'); }); // 如果第二个参数提供了数组,数组中只能是state的值或者props的值 // 只有依赖发生变化,回来哦函数才执行。并且判断是否发生变化,比较的是状态的引用。 useEffect(()=>{ console.log('2 useEffect run.......'); }, [value, props.data]); // 如果第二个参数为空数组,那么第一个回调就相当于class组件的componentDidMount useEffect(()=>{ console.log('3 useEffect run.......'); //而且在effect函数中是可以拿到DOM对象的 }, []); useEffect(()=>{ console.log('4 useEffect run.......'); console.log(document.querySelector('#flag').innerHTML); // 返回的函数,会在下一次渲染完组件后,执行下一次的useEffect前,先调用上一次返回的useEffect返回的函数。 return (...rest)=>{ console.log('4 useEffect return func run.......'); console.log(document.querySelector('#flag').innerHTML); } }); useEffect(()=>{ console.log('5 useEffect run.......'); return ()=>{ // 当依赖为空时,useEffect返回的函数,相当于class组件的componentWillUnmount console.log('5 useEffect return func run.......'); } }, []); //暂时Hook 只能模拟这几个钩子函数 3、useRef 用来拿到DOM对象,类组件中的 React.createRef 一样。 import React, { useRef } from 'react' ... //下面是函数组件内部代码 let h4DOM = useRef(); return ( //用法和类组件中一样,都是从current中取值。 <h4 ref={h4DOM}>test</h4> // console.log(h4DOM.current); ) 4、useContext 提供数据的用法和类组件是一样的,不同点在于消费数据。 //初始化仓库数据,可以用useState,同时提供数据和修改数据的方法。 const [value, setValue] = useState(1) <DataContext.Provider value={{ value, setValue, //将属性和修改属性的方法,一起存在仓库中 }} > <div className="app"> <One /> <hr /> <Two /> </div> </DataContext.Provider> //调用的时候 import React, {useContext} from 'react' import DataContext from '../context/DataContext' import ThemeContext from '../context/ThemeContext' export default function Two() { const context = useContext(DataContext); console.log(context); const context2 = useContext(ThemeContext); console.log(context2); return ( <div> <h1>{context.value}</h1> <button onClick={()=>{ context.setValue(context.value+1); }}>修改</button> </div> ) } 5、useCallback 该hook,保证了某一些特殊函数,只执行一次,避免过多执行而消耗性能,第一个参数是想只执行一次的函数体,第二个参数可以是函数体用到的依赖状态。 import React, { useEffect, useState, useCallback } from 'react' const list = []; export default function App() { console.log('render.....'); const [value, setValue] = useState(''); // useCallback作用:声明一次函数,当组件再次渲染,取上次渲染时声明的函数直接使用。 // 但是,当依赖发生变化时,又会重新声明一次函数。 // 如果在组件中定义局部的函数,那么就是用useCallback包裹,注意useCallback的依赖一定要正确。 const valueChange = useCallback((ev)=>{ console.log(value); setValue(ev.target.value); }, [value]); useEffect(()=>{ list.push(valueChange); console.log(list.length); if(list.length === 2){ console.log(list[0] === list[1]); } }); return ( <div className="app"> <h1>value: {value}</h1> <input type="text" value={value} onChange={valueChange}/> </div> ) } 6、useMemo 相当于计算属性,只有依赖的值发生变化,才会执行memo包裹的函数。 import React, { useState, useCallback, useMemo, memo } from "react"; function One() { console.log("render............"); const [a, setA] = useState(1); const [b, setB] = useState(2); const [c, setC] = useState(3); const list = []; // useMemo相当于计算属性 // 第一个参数是个函数,需要返回计算的属性,第二个参数是依赖,依赖发生变化,重新计算属性。 const result = useMemo(() => { // 计算属性的代码 var result = 100; for (var i = 1; i <= a && i <= b; i++) { console.log("计算最大公约数..."); if (a % i === 0 && b % i === 0) { result = i; } } // 计算得到的属性,需要返回出去 return result; }, [a, b]); console.log(result); const btn1Action = useCallback(() => { setA((a) => a + 1); }, []); const btn2Action = useCallback(() => { setB((b) => b + 1); }, []); const btn3Action = useCallback(() => { setC((c) => c + 1); }, []); return ( <div> <p>A: {a}</p> <p>b: {b}</p> <p>AB的最大公约数:{result}</p> <p>c: {c}</p> <button onClick={btn1Action}>修改A</button> <button onClick={btn2Action}>修改B</button> <button onClick={btn3Action}>修改C</button> </div> ); } export default memo(One); 7、useHistory 与 useLocation 与 useMatch 用来获取路由参数,相当于类组件中的 withRouter 高阶组件。 import React from "react"; import { useHistory, useLocation ,useRouteMatch ,useParams } from "react-router-dom"; //在类组件中除了 利用 component 属性来跳转的路由,其他都拿不到上面三个属性,需要用到高阶组件 withRouter包裹才能用到。 //利用Hook 就可以直接拿到。但是要是在Router的包裹范围内。 export default function Two(props) { const history = useHistory(); console.log(history); const location = useLocation(); console.log(location); } 8 、useSelect 与 useDispatch 与 useStore 用来获取store中的数据和方法。类组件中用到高阶组件 content import React from 'react' import { useCallback } from 'react'; import {useSelector, useDispatch, useStore} from 'react-redux' export default function One(props) { // 获取redux仓库中的数据 const val = useSelector(state=>{ return state.value; }); // 获取dispatch const dispatch = useDispatch(); const btnAction = useCallback(()=>{ dispatch({type: 'modify-value', value: 'hello'}); }, [dispatch]); // 获得仓库 const store = useStore(); console.log(store); return ( <div className="one"> <h1>one组件</h1> <h2>{val}</h2> <button onClick={btnAction}>修改value</button> </div> ) }
最新回复(0)