useState
会返回一对值:当前状态和一个让你更新它的函数useState
唯一的参数就是初始state
let lastStatefunction useState(initialState) {lastState = lastState || initialStatefunction setState(newState) {lastState = newStaterender()}return [lastState, setState]}
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()
let hookStates = []let hookIndex = 0function useState(initialState) {//如果有老值取老值,没有取默认值hookStates[hookIndex] = hookStates[hookIndex] || initialState//暂存索引let currentIndex = hookIndexfunction setState(newState) {hookStates[currentIndex] = newStaterender()}return [hookStates[hookIndex++], setState]}
Effect Hook
,给函数组件增加了操作副作用的能力componentDidMount
、componentDidUpdate
和componentWillUnmount
具有相同的用途,只不过被合并成了一个 APIlet hookStates = []let hookIndex = 0function useState(initialState) {//如果有老值取老值,没有取默认值hookStates[hookIndex] = hookStates[hookIndex] || initialState//暂存索引let currentIndex = hookIndexfunction setState(newState) {hookStates[currentIndex] = newStaterender()}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++] = dependenciessetTimeout(callback)}} else {hookStates[hookIndex++] = dependenciessetTimeout(callback)}}
useEffect
相同,但它会在所有的DOM
变更之后同步调用 effectuseEffect
不会阻塞浏览器渲染,而useLayoutEffect
会阻塞浏览器渲染useEffect
会在浏览器渲染结束后执行,useLayoutEffect
则是在DOM
更新完成后,浏览器绘制之前执行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()
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++] = dependenciesqueueMicrotask(callback)}} else {hookStates[hookIndex++] = dependenciesqueueMicrotask(callback)}}
context
对象并返回该context
的当前值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()
function useContext(context) {return context._currentValue}
import React from "react"import ReactDOM from "react-dom"function reducer(state, action) {switch (action.type) {case "increment":return state + 1case "decrement":return state - 1default: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()
let hookStates = []let hookIndex = 0function useReducer(reducer, initialState) {hookStates[hookIndex] = hookStates[hookIndex] || initialStatelet currentIndex = hookIndexfunction dispatch(action) {hookStates[currentIndex] = reducer(hookState[currentIndex], action)render()}return [hookStates[hookIndex++], dispatch]}