二.React(hooks)

1.useState

  • useState会返回一对值:当前状态和一个让你更新它的函数
  • useState唯一的参数就是初始state

1.1 使用

0

1.2 实现

let lastState
function useState(initialState) {
lastState = lastState || initialState
function setState(newState) {
lastState = newState
render()
}
return [lastState, setState]
}

2.多 useState

2.1 使用

import React from "react"
import ReactDOM from "react-dom"
function Counter() {
const [number1, setNumber1] = React.useState(0)
const [number2, setNumber2] = React.useState(0)
return (
<>
<p>{number1}</p>
<button onClick={() => setNumber1(number1 + 1)}>+</button>
<hr />
<p>{number2}</p>
<button onClick={() => setNumber2(number2 + 1)}>+</button>
</>
)
}
function render() {
ReactDOM.render(<Counter />, document.getElementById("root"))
}
render()

2.2 实现

let hookStates = []
let hookIndex = 0
function useState(initialState) {
//如果有老值取老值,没有取默认值
hookStates[hookIndex] = hookStates[hookIndex] || initialState
//暂存索引
let currentIndex = hookIndex
function setState(newState) {
hookStates[currentIndex] = newState
render()
}
return [hookStates[hookIndex++], setState]
}

3.useEffect

  • useEffect 就是一个Effect Hook,给函数组件增加了操作副作用的能力
  • 它跟 class 组件中的componentDidMountcomponentDidUpdatecomponentWillUnmount具有相同的用途,只不过被合并成了一个 API

3.1 componentDidMount 场景

进入页面等待5秒:接口数据请求中...

3.2 componentDidUpdate 场景

小明

:0

3.3 componentWillUnmount 场景

:小明

:0

3.2 实现

let hookStates = []
let hookIndex = 0
function useState(initialState) {
//如果有老值取老值,没有取默认值
hookStates[hookIndex] = hookStates[hookIndex] || initialState
//暂存索引
let currentIndex = hookIndex
function setState(newState) {
hookStates[currentIndex] = newState
render()
}
return [hookStates[hookIndex++], setState]
}
function UseEffect(callback, dependencies) {
if (hookStates[hookIndex]) {
let lastDeps = hookStates[hookIndex]
let same = dependencies.every((item, index) => item === lastDeps[index])
if (same) {
hookIndex++
} else {
hookStates[hookIndex++] = dependencies
setTimeout(callback)
}
} else {
hookStates[hookIndex++] = dependencies
setTimeout(callback)
}
}

4.useLayoutEffect

  • 其函数签名与useEffect相同,但它会在所有的DOM变更之后同步调用 effect
  • useEffect不会阻塞浏览器渲染,而useLayoutEffect会阻塞浏览器渲染
  • useEffect会在浏览器渲染结束后执行,useLayoutEffect则是在DOM更新完成后,浏览器绘制之前执行

4.1 使用

import React from "react"
import ReactDOM from "react-dom"
const Animate = () => {
const red = React.useRef()
const green = React.useRef()
React.useLayoutEffect(() => {
red.current.style.transform = `translate(500px)`
red.current.style.transition = `all 500ms`
})
React.useEffect(() => {
green.current.style.transform = `translate(500px)`
green.current.style.transition = `all 500ms`
})
let style = { width: "100px", height: "100px" }
return (
<div>
<div style={{ ...style, backgroundColor: "red" }} ref={red}></div>
<div style={{ ...style, backgroundColor: "green" }} ref={green}></div>
</div>
)
}
function render() {
ReactDOM.render(<Animate />, document.getElementById("root"))
}
render()

4.2 实现

function useLayoutEffect(callback, dependencies) {
if (hookStates[hookIndex]) {
let lastDeps = hookStates[hookIndex]
let same = dependencies.every((item, index) => item === lastDeps[index])
if (same) {
hookIndex++
} else {
hookStates[hookIndex++] = dependencies
queueMicrotask(callback)
}
} else {
hookStates[hookIndex++] = dependencies
queueMicrotask(callback)
}
}

5.useContext

  • 接收一个context对象并返回该context的当前值

5.1 使用

import React from "react"
import ReactDOM from "react-dom"
const CounterContext = React.createContext()
function Counter() {
let { state, setState } = React.useContext(CounterContext)
return (
<>
<p>{state.number}</p>
<button onClick={() => setState({ number: state.number + 1 })}>+</button>
<button onClick={() => setState({ number: state.number - 1 })}>-</button>
</>
)
}
function App() {
const [state, setState] = useState({ number: 0 })
return (
<CounterContext.Provider value={{ state, setState }}>
<Counter />
</CounterContext.Provider>
)
}
function render() {
ReactDOM.render(<App />, document.getElementById("root"))
}
render()

5.2 实现

function useContext(context) {
return context._currentValue
}

6.useReducer

  • 它接收一个形如(state,action)=> newState 的 renducer,并返回当前的 state 以及与其配套的 dispatch 方法

6.1 使用

import React from "react"
import ReactDOM from "react-dom"
function reducer(state, action) {
switch (action.type) {
case "increment":
return state + 1
case "decrement":
return state - 1
default:
throw new Error()
}
}
function Counter() {
const [state, dispatch] = React.useReducer(reducer, 0)
return (
<>
Count: {state}
<button onClick={() => dispatch({ type: "increment" })}>+</button>
<button onClick={() => dispatch({ type: "decrement" })}>-</button>
</>
)
}
function render() {
ReactDOM.render(<Counter />, document.getElementById("root"))
}
render()

6.2 实现

let hookStates = []
let hookIndex = 0
function useReducer(reducer, initialState) {
hookStates[hookIndex] = hookStates[hookIndex] || initialState
let currentIndex = hookIndex
function dispatch(action) {
hookStates[currentIndex] = reducer(hookState[currentIndex], action)
render()
}
return [hookStates[hookIndex++], dispatch]
}

7.useMemo

7.1 使用

7.2 实现

8.useCallback

8.1 使用

8.2 实现