Read the source code of React-8
ReactHooks
Hook
yesReact 16.8
New features for. It allows you to writeclass
Use in case ofstate
And othersReact
Characteristic.import { useCallback, useContext, useEffect, useImperativeHandle, useDebugValue, useLayoutEffect, useMemo, useReducer, useRef, useState, useResponder, } from './ReactHooks';
useState
useState returns a pair of values: the current state and a function that lets you update it, which you can call in the event handler or elsewhere
It is similar to this.setState of the class component, but it will not merge the new state with the old state;
import React, { useState } from "react"; import "./App.css"; function App() { const [count, setCount] = useState(0); return ( <div className="App"> <div> <p>You clicked {count} times</p> <button onClick={() => setCount(count + 1)}>Click me</button> </div> </div> ); } export default App;
useEffect
import React, { useState, useEffect } from "react"; import "./App.css"; function App() { const [count, setCount] = useState(0); useEffect(() => { // Update the document title using the browser API document.title = `You clicked ${count} times`; }); return ( <div className="App"> <div> <p>You clicked {count} times</p> <button onClick={() => setCount(count + 1)}>Click me</button> </div> </div> ); } export default App;
Equivalent to the life cycle function of React class, you can think of useEffect Hook as a combination of three functions: componentDidMount, componentDidUpdate and componentWillUnmount.
By default, effect is executed after each round of component rendering. In this case, once
If the dependency of effect changes, it will be recreated.
A second parameter can be passed to useEffect, which is an array of values on which effect depends. The updated example is as follows:
useEffect( () => { const subscription = props.source.subscribe(); return () => { subscription.unsubscribe(); }; }, [props.source], );
If you want to execute an effect that runs only once (only when the component is mounted and unloaded), you can pass an empty array ([]) as the second parameter. This tells React that your effect does not depend on any value in props or state, so it never needs to be repeated. This is not a special case - it still follows the way input arrays work.
useContext
Similar to the Context mentioned before
const value = useContext(MyContext);
Receives a context object (the return value of React.createContext) and returns the current value of the context. The current context value is determined by the value prop of < mycontext. Provider > closest to the current component in the upper component
const themes = { light: { foreground: "#000000", background: "#eeeeee" }, dark: { foreground: "#ffffff", background: "#222222" } }; const ThemeContext = React.createContext(themes.light); function App() { return ( <ThemeContext.Provider value={themes.dark}> <Toolbar /> </ThemeContext.Provider> ); } function Toolbar(props) { return ( <div> <ThemedButton /> </div> ); } function ThemedButton() { const theme = useContext(ThemeContext); return ( <button style={{ background: theme.background, color: theme.foreground }}> I am styled by theme context! </button> ); }
useContext
Argument to must becontext
Object itself
useReducer
const [state, dispatch] = useReducer(reducer, initialArg, init);
Receive a reducer with the shape (state, action) = > newstate, and return the current state and its matching dispatch method.
Similar to redux.
Implemented counters
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 App() { const [state, dispatch] = useReducer(reducer, initialState); return ( <> Count: {state.count} <button onClick={() => dispatch({ type: "decrement" })}>-</button> <button onClick={() => dispatch({ type: "increment" })}>+</button> </> ); }
Specify the initial state
const [state, dispatch] = useReducer( reducer, {count: initialCount} );
lazy initialization
You can choose to create the initial state lazily. To do this, you need to pass in the init function as the third parameter of useReducer, so that the initial state will be set to init(initialArg).
function init(initialCount) { return {count: initialCount}; } function reducer(state, action) { switch (action.type) { case 'increment': return {count: state.count + 1}; case 'decrement': return {count: state.count - 1}; case 'reset': return init(action.payload); default: throw new Error(); } } function App({initialCount}) { const [state, dispatch] = useReducer(reducer, initialCount, init); return ( <> Count: {state.count} <button onClick={() => dispatch({type: 'reset', payload: initialCount})}> Reset </button> <button onClick={() => dispatch({type: 'decrement'})}>-</button> <button onClick={() => dispatch({type: 'increment'})}>+</button> </> ); }
Skip dispatch
If the return value of Reducer Hook is the same as the current state, React will skip the rendering of subcomponents and the execution of side effects.
React uses the Object.is comparison algorithm to compare state
useCallback
When the inline callback function and dependency array are passed into useCallback as parameters, it will return the remembered version of the callback function, which will be updated only when a dependency changes. It's useful when you pass a callback function to an optimized subcomponent that uses referential equality to avoid unnecessary rendering, such as shouldComponentUpdate.
const memoizedCallback = useCallback( () => { doSomething(a, b); }, [a, b], );
useRef
useRef returns a variable ref object whose. current property is initialized to the passed in parameter (initialValue). The returned ref object remains unchanged throughout the life of the component.
It's similar to the previous ref,forwardref,createref, except that it's in the function component.
function TextInputWithFocusButton() { const inputEl = useRef(null); const onButtonClick = () => { //'current' points to a text input element that has been mounted to the DOM inputEl.current.focus(); }; return ( <> <input ref={inputEl} type="text" /> <button onClick={onButtonClick}>Focus the input</button> </> ); }
useMemo
const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);
Pass the create function and dependency array as parameters to useMemo, which recalculates the remembered value only when a dependency changes. This optimization helps to avoid high overhead calculations every time you render.
Similar to memo
Other API
It's almost the same without a narrative.