https://react.docschina.org/docs/hooks-intro.html
Hook 是能让你在函数组件中“钩入” React 特性的函数。它们名字通常都以 use 开始
React使用hook动机:
1.在组件之间复用状态逻辑很难
2.复杂组件变得难以理解
3.class学习成本比较高
4.Hook 其中一个目的就是要解决 class 中生命周期函数经常包含不相关的逻辑
https://react.docschina.org/docs/hooks-intro.html#motivation
使用hook需要注意的事项
https://react.docschina.org/docs/hooks-rules.html
1.不能在Class组件中使用
2.只能在函数最外层调用,不能在循环、条件和子函数中调用
原因:如果Hook 的调用顺序在多次渲染之间不保持,React 就不能正确地将内部 state 和对应的 Hook 进行关联。
3.只能在React函数组件中调用,不能在其他的js函数中调用
官方推荐该插件eslint-plugin-react-hooks 来检测使用的hook是否符合要求
正式介绍Hook
useState
useEffect
useEffect 可以在组件渲染后实现各种不同的副作用。有些副作用可能需要清除,所以需要返回一个函数:
其实 useState useEffect应该可以解决绝大多数问题
useContext:
import React, { useState, useEffect, useRef, createContext,useContext} from 'react';
// 创建一个context
const CountContext = createContext()
function Example() {
const [count, setCount] = useState(0);
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>
Click me
</button>
{/* 父组件中 */}
<CountContext.Provider value={count}>
<Counter></Counter>
</CountContext.Provider>
</div>
);
}
// 声明一个子组件
function Counter() {
// 子组件中使用
let count = useContext(CountContext)
return (
<div class="count-div">{count}</div>
)
}
export default Example
useReducer
https://zh-hans.reactjs.org/docs/hooks-reference.html#usereducer
起源于redux中的reducer,是useState 的替代方案。它接收一个形如 (state, action) => newState 的 reducer,并返回当前的 state 以及与其配套的 dispatch 方法。(如果你熟悉 Redux 的话,就已经知道它如何工作了。)
import React, { useReducer} from 'react';
function CountReducer() {
const [count,dispatch] =useReducer((state, action)=> {
switch (action) {
case 'add':
// debugger
return state+1
case 'minus':
return state-1
default:
return state
}
}, 0)
return (
<div>
<button onClick={()=>dispatch('add')}>+</button>
<button onClick={()=>dispatch('minus')}>-</button>
{count}
</div>
)
}
export default CountReducer
自定义hook
hook.js
import React, {useEffect, useState, useCallback}from 'react'
export function useWinSize () {
const [size, setSize] = useState({
width: document.documentElement.clientWidth,
height: document.documentElement.clientHeight
})
const onResize = useCallback(() => {
setSize({
width: document.documentElement.clientWidth,
height: document.documentElement.clientHeight
})
})
useEffect(()=>{
window.addEventListener('resize', onResize)
return()=>{
window.removeEventListener('resize', onResize)
}
},[])
return size
}
使用
import {useWinSize} from './hook.js'
function Example3 () {
const size = useWinSize()
return(
<div>页面size:width:{size.width}height{size.height}</div>
)
}
export default Example3
useReducer+useContext代替Redux小案例
使用useContext控制状态 和useReducer传递逻辑函数
颜色(state)管理的代码我们都放在了color.js中,所以在文件里添加一个reducer,用于处理颜色更新的逻辑。先声明一个reducer的函数,它就是JavaScript中的普通函数,有了reducer后,在Color组件里使用useReducer,这样Color组件就有了那个共享状态和处理业务逻辑的能力,跟以前使用的Redux几乎一样了
example.js(父组件)
import React, { Component } from 'react';
import Buttons from './Buttons'
import ShowArea from './ShowArea'
import './index.css'
import {Color} from './Color'
function Example6(params) {
return (
<div>
<Color>
<Buttons/>
<ShowArea/>
</Color>
</div>
)
}
export default Example6
Color.js管理整体通信的组件
import React, { Component, createContext, useReducer } from 'react';
export const ColorContext = createContext()
const reducer = (state, action)=>{
switch (action.type) {
case 'colorType':
return action.color
default:
return state
}
}
export const Color =props=> {
const [color, dispatch] = useReducer(reducer, 'blue')
return (
<div>
<ColorContext.Provider value={{color, dispatch}}>
{props.children}
</ColorContext.Provider>
</div>
)}
兄弟组件1
import React, { Component, useContext } from 'react';
import {ColorContext} from './Color'
import './index.css'
function ShowArea() {
const {color} = useContext(ColorContext)
return (<div><div style={{color: color}}>nihao{color}</div></div>)
}
export default ShowArea
兄弟组件2
import React, { Component,useContext } from 'react';
import {ColorContext} from './Color'
function Buttons(params) {
const {dispatch} = useContext(ColorContext)
return(
<div>
<button onClick={()=>{dispatch({type: 'colorType',color:'red'})}}>红色</button>
<button onClick={()=>{dispatch({type: 'colorType',color:'blue'})}}>蓝色</button>
</div>)
}
export default Buttonsimport React, { Component,useContext } from 'react';
import {ColorContext} from './Color'
function Buttons(params) {
const {dispatch} = useContext(ColorContext)
return(
<div>
<button onClick={()=>{dispatch({type: 'colorType',color:'red'})}}>红色</button>
<button onClick={()=>{dispatch({type: 'colorType',color:'blue'})}}>蓝色</button>
</div>)
}
export default Buttons
实现按钮切换
自己的理解关于useReducer+useContext代替Redux(仅个人见解,详细的请小伙伴看官方文档自行理解)
首先需要createContext返回一个对象,使用ColorContext.Provider将要传递的值或者函数提供出去,在对应的组件通过useContext拿到,通过useReducer提供的dispatch改变值的状态
使用ref保存状态
import React, { Component, useMemo,useRef,useState,useEffect } from 'react';
export function Example8(params) {
// useRef可以保存变量
// const refInput = useRef('')
// const onButtonClick = ()=> {
// refInput.current.value ='你好'
// }
const textRef = useRef()
const [text, setText] = useState()
useEffect(()=>{
textRef.current = text
console.log(textRef.current, 'textRef.current.text')
})
return (
<>
{/* <input type="text" ref={refInput}></input> */}
{/* <button onClick={onButtonClick}>展示文字input</button> */}
<input value={text} onChange={(e)=>{setText(e.target.value)}}></input>
</>
)
}