react hook总结
Hook 是 React 16.8 的新增特性。它可以让你在不编写 class 的情况下使用 state 以及其他的 React 特性。
0.概念
纯函数
前言:什么是纯函数?
纯函数需要满足一下两个条件:
什么又叫做函数的副作用呢?
具有以下几个等特征就是函数的副作用:
- 函数内部修改了外部的变量以及数据
- 函数内部抛出错误
- 函数内部与控制台和屏幕有交互
- 函数对文件进行写入与读写
- 调用其他具有副作用的函数
- 触发任何外部进程
- …
1、useState 保存组件状态
useState(0)把当前变量的初始值保存下来了,setCount的主要作用修改当前状态,类似于class组件中的 this.setState({})
import React, { useState } from 'react';
export default function Example(){
// 声明一个新的叫做 “count” 的 state 变量
let [count, setCount] = useSate(0)
return (
<>
<h1>当前值是{count}</h1>
<button onClick={()=> setCount(count + 1)>++</button>
</>
)
}
2.useEffect 生命周期
useEffect 相当于类组件得 componentDidMount,componentDidUpdate, componentWillUnmount 等生命周期
import React, { useEffect, useState } from "react";
// 组件路径
import { Route, Link, BrowserRouter as Router } from "react-router-dom"
import Home from "./pages/Home/index";
import List from "./pages/List/index";
function Home(){
let [count, setCount] = useState(0)
useEffect(()=>{
console.log("Home===>我来了")
return () => {
console.log("Home======>我走啦")
}
},[])
return (
<>
<h1>home</h1>
<h2>{count}</h2>
<button onClick={()=>setCount(count+1)}></button>
</>
)
}
function Message(){
return (
<>
<h1>Message</h1>
</>
)
}
function App(){
return (
<>
<h1>App</h1>
<div>
<Link to="/home">Home</home>
<Link to="/message">message</home>
<hr/>
<Router>
<Route path="/home" component={Home} />
<Route path="/message" component={Message} />
</Router>
</div>
</>
)
}
export default App
3.createContext
函数组件和 class 组件中 React.createContext() 的使用
-
函数组件 GrandContext.jsx import React, { createContext } from 'react'
export default createContext()
App 父组件 import React,{ useState, useEffect, createContext } from 'react'
import Home '../Home/index.jsx'
import GrandContext '../utils/GrandContext.jsx'
export default function App() {
let [count, setCount] = useState(0)
return (
<>
<context.Provider value={ count } >
<h1>这里是 App 组件</h1>
<Home />
<context.Provider>
</>
)
}
Home.jsx import React,{ useContext } from 'react'
import GrandContext '../utils/GrandContext.jsx'
function Home() {
let context = useContext(GrandContext)
return (
<>
<h1>这里是 home 组件,收到的值为 { context } </h1>
</>
)
}
-
class 组件 GrandContext.jsx import React, { createContext } from 'react'
export default createContext()
App.jsx import React from "react";
import Message from "./pages/Message";
import GrandParentContext from "./utils/GrandParentContext";
class App extends React.Component {
render() {
return (
<div>
<h1>App</h1>
<GrandParentContext.Provider value={context}>
<Message />
</GrandParentContext.Provider>
</div>
)
}
}
Message.jsx import React from "react";
import GrandParentContext from "./utils/GrandParentContext";
class Message extends React.Component {
static contextType = GrandParentContext;
render() {
return (
<div>当前数字是{this.context}</div>
)
}
}
4.useReducer
const [state, dispatch] = useReducer(reducer, initialArg, init);
useState 的替代方案。它接收一个形如 (state, action) => newState 的 reducer,并返回当前的 state 以及与其配套的 dispatch 方法。(如果你熟悉 Redux 的话,就已经知道它如何工作了。在某些场景下,useReducer 会比 useState 更适用,例如 state 逻辑较复杂且包含多个子值,或者下一个 state 依赖于之前的 state 等。并且,使用 useReducer 还能给那些会触发深更新的组件做性能优化,因为你可以向子组件传递 dispatch 而不是回调函数 。
const initialState = {count: 0};
function reducer(state, action) {
switch (action.type) {
case 'increment':
return {count: state.count + 1};
case 'decrement':
return {count: state.count - 1};
default:
throw new Error();
}
}
function Counter() {
const [state, dispatch] = useReducer(reducer, initialState);
return (
<>
Count: {state.count}
<button onClick={() => dispatch({type: 'decrement'})}>-</button>
<button onClick={() => dispatch({type: 'increment'})}>+</button>
</>
);
}
5.useMeua
主要是对 组件 或状态的缓存,被缓存的组件 不会随着 state 的更新而变动,computeExpensiveValue 为缓存的组件,[a, b]为缓存组件触发的条件,只有当 a 或 b 变化时,才会useMeua,重新渲染 computeExpensiveValue
const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);
案例:
function Foo(props) {
console.log('foo', props);
return (
<ul>
{props.render()}
</ul>
)
}
export default function Message() {
const [num, setNum] = useState(0)
const [Count, setCount] = useState(5)
const render = useCallback(() => {
console.log('render', Count);
let newArr2 = []
for (let i = 0; i < Count; i++) {
newArr2.push(<li key={i}>{i}</li>)
}
return newArr2
}, [])
return (
<div>
<h1>count: {num} ---- </h1>
<button onClick={() => setNum(num + 1)}> ++1 </button>
{ useMemo(() => <Foo render={render} />, [Count]) }
</div>
)
}
6.useCallBack
主要是对 方法的缓存,有两个参数,doSomething 为缓存的方法,[a, b] 为触发方法重新执行的条件,只有当 a 或 b 执行时,才可以使得useCallback 重新执行
const memoizedCallback = useCallback( () => { doSomething(a, b); }, [a, b] );
案例:
function Foo(props) {
console.log('foo', props);
return (
<ul>
{props.render()}
</ul>
)
}
export default function Message() {
const [num, setNum] = useState(0)
const [Count, setCount] = useState(5)
const render = useCallback(() => {
console.log('render', Count);
let newArr2 = []
for (let i = 0; i < Count; i++) {
newArr2.push(<li key={i}>{i}</li>)
}
return newArr2
}, [])
return (
<div>
<h1>count: {num} ---- </h1>
<button onClick={() => setNum(num + 1)}> ++1 </button>
{ useMemo(() => <Foo render={render} />, [Count]) }
</div>
)
}
7.自定义 hook
自定义hook是react16.8新出来的新特性, 把组件中相同的逻辑单独抽离出一个公用的组件
import React, { useState, useCallback, useEffect } from 'react'
// 自定义 hook 命名必须以 use 开头
function UseFoo(){
const [size, setSize] = usestate({
width: document.documentElement.clientWidth,
height: document.documentElement.clientHeight
})
const sizeChange = useCallback( ()=>{
setSize({
width: document.documentElement.clientWidth,
height: document.documentElement.clientHeight
})
},[])
useEffect(()=>{
window.addEventListener("resize", sizeChange)
return ()=>{
window.removeEventListener("resize", sizeChange)
}
},[])
return size
}
export default function index() {
let Foo = UseFoo()
return (
<div>size: { Foo.width } x { Foo.height }</div>
)
}
|