useState
用来声明状态变量。
import React, { useState } from 'react'; // ... const [ count , setCount ] = useState(0); // ...
- count 声明的变量
- setCount 设用来更新变量的函数
- 0 初始值
- 多个状态声明不能出现在条件判断语句中
useEffect
用来代替生命周期函数。
import React, { useEffect } from 'react'; useEffect(()=>{ // some code })
- 第一次组件渲染和每次组件更新都会执行这个函数
- useEffect中的函数的执行不会阻碍浏览器更新视图,这些函数是异步的
使用 useEffect 实现类似 componentWillUnmount
useEffect(()=>{ return () => { // some code } })
- 返回一个函数实现解绑
- 但是这样会导致每次状态发生变化,useEffect 都进行解绑
useEffect(()=>{ return () => { // some code } }, [])
使用第二个参数,制定哪些状态发生变化时再解绑
useContext
跨越组件层级直接传递变量,实现状态共享。
- useContext 解决的是组件之间值传递的问题
- redux 解决的是应用中统一管理状态的问题
- useContext 通过和 useReducer 的配合使用,可以实现类似 Redux 的作用
Outer 组件
import React, { createContext } from 'react' const ValueContext = createContext() function Outer(){ return ( <> <ValueContext.Provider value={'我是传向 Inner 组件的值'}> <Inner /> </ValueContext.Provider> </> ) } export default Outer;
- 使用 createContext 创建 context
- 使用 createContext 同时生成组件
- 闭合标签将组件包裹
Inner 组件
import React, { useContext } from 'react' const value = useContext(CountContext) function Inner(){ return ( <> <p>{value}</p> </> ) } export default Inner;
使用 useContext 来使用上下文
useReducer
用来实现类似 redux 功能
import React, { useReducer } from 'react'; function Demo(){ const [ count, dispatch ] = useReducer((state,action)=>{ switch(action){ case 'add': return state+1 case 'sub': return state-1 default: return state } },0) return ( <> <h2>分数:{count}</h2> <button onClick={()=>dispatch('add')}>加</button> <button onClick={()=>dispatch('sub')}>减</button> </> ) } export default Demo
- state 第一个参数 状态
- action 控制业务逻辑的判断参数
模拟 Redux
- useContext:可访问全局状态,避免一层层的传递状态
- useReducer:通过action的传递,更新复杂逻辑的状态
颜色共享组件 color.js
import React, { createContext,useReducer } from 'react'; export const ColorContext = createContext({}) export const UPDATE_COLOR = 'UPDATE_COLOR' const reducer = (state, action) => { switch(action.type){ case UPDATE_COLOR: return action.color default: return state } } export const Color = props => { const [color, dispatch] = useReducer(reducer, 'blue') return ( <ColorContext.Provider value = {{color,dispatch}}> {props.children} </ColorContext.Provider> ) }
- 用 {props.children} 来显示子组件
- 将 color 和 dispatch 共享出去
showArea.js
import React , { useContext } from 'react'; import { ColorContext } from './color'; function ShowArea(){ const { color } = useContext(ColorContext) return (<div style={{ color:color }}>字体颜色为{ color }</div>) } export default ShowArea
- 注意 引入 ColorContext 使用了大括号
Buttons.js
import React , { useContext } from 'react'; import { ColorContext, UPDATE_COLOR } from './color' function Buttons(){ const { dispatch } = useContext(ColorContext) return ( <div> <button onClick={()=>{dispatch({type:UPDATE_COLOR,color:"red"})}}>红色</button> <button onClick={()=>{dispatch({type:UPDATE_COLOR,color:"yellow"})}}>黄色</button> </div> ) } export default Buttons
Demo.js
import React, { useReducer } from 'react'; import ShowArea from './ShowArea'; import Buttons from './Buttons'; import { Color } from './color'; //引入Color组件 function Demo(){ return ( <> <Color> <ShowArea /> <Buttons /> </Color> </> ) } export default Demo
useMemo
用来解决使用 React hooks 产生的无用渲染的性能问题。
import React , {useState,useMemo} from 'react'; function Demo(){ const [xiaohong , setXiaohong] = useState('小红待客状态') const [zhiling , setZhiling] = useState('志玲待客状态') return ( <> <button onClick={()=>{setXiaohong(new Date().getTime())}}>小红</button> <button onClick={()=>{setZhiling(new Date().getTime()+',志玲向我们走来了')}}>志玲</button> <ChildComponent name={xiaohong}>{zhiling}</ChildComponent> </> ) } function ChildComponent({name,children}){ function changeXiaohong(name){ console.log('她来了,她来了。小红向我们走来了') return name+',小红向我们走来了' } const actionXiaohong = changeXiaohong(name) return ( <> <div>{actionXiaohong}</div> <div>{children}</div> </> ) } export default Demo
点击志玲按钮,小红对应的方法执行,虽然结果没变,但是每次都执行,损耗性能。
function ChildComponent({name,children}){ function changeXiaohong(name){ console.log('她来了,她来了。小红向我们走来了') return name+',小红向我们走来了' } const actionXiaohong = useMemo(()=>changeXiaohong(name),[name]) return ( <> <div>{actionXiaohong}</div> <div>{children}</div> </> ) }
第二个参数 [name] 匹配成功,才会执行。
useRef
- 用来获取React JSX中的DOM元素
- 用来保存变量
import React, { useRef} from 'react'; function Demo(){ const inputEl = useRef(null) inputEl.current.value = "给 input value属性 赋值" return ( <> <input ref={inputEl} type="text"/> </> ) } export default Demo
import React, { useRef, useState, useEffect } from 'react' function Demo(){ const inputEl = useRef(null) inputEl.current.value="给 input value属性 赋值" const [text, setText] = useState('默认值') const textRef = useRef() useEffect(()=>{ textRef.current = text }) return ( <> <input ref={inputEl} type="text"/> <input value={text} onChange={(e)=>{setText(e.target.value)}} /> </> ) } export default Demo
- text 每次发生变化,将值保存到 useRef 中
- 使用 useEffect 实现每次状态变化都进行变量重新赋值
- 很少用到这个功能(保存变量)
自定义 Hooks
编写自定义函数实现获取浏览器窗口
import React, { useState, useEffect, useCallback } from 'react'; 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; } function Demo(){ const size = useWinSize() return ( <div>页面Size:{size.width} x {size.height}</div> ) } export default Demo
- 命名要使用 use 开头以确认该函数是自定义 Hook 而不是组件
- useCallback 用来缓存方法 ( useMemo 是为了缓存变量)
- 第一次进入方法时用 useEffect 来注册 resize 监听事件
- 防止一直监听所以在方法移除时,使用return的方式移除监听
- 最后在 Demo 组件中使用
文章参考
- 官方文档
- 哔哩哔哩up主技术胖的 视频