React has two sets of apis: the Class API and the function-based hooks API. It is officially recommended to use hooks instead of classes. Because hooks are cleaner and require less code, they are “light” to use and classes are “heavy”. Also, hooks are functions, which are more in line with the React function nature.
Try to write components as pure functions. If you need external functions and side effects, use hooks to “hook” external code. React Hooks are those Hooks.
Class and function differences
-
A class is an encapsulation of data and logic. That is, the state and operation methods of a component are encapsulated together. If you choose a class, you should write all the relevant data and operations in the same class.
-
In general, a function should only do one thing, and that is return a value. If you have multiple operations, each operation should be written as a separate function. Furthermore, the state of the data should be separated from the method of operation. According to this philosophy, the React function component should only do one thing: return the component’s HTML code, and nothing else.
What are the side effects
function Welcome(props) {
return <h1>Hello, {props.name}</h1>;
}
Copy the code
This function does only one thing: it returns the HTML code of the component based on the input parameters. Functions that perform pure calculations (conversions) are called “pure functions” in functional programming, so where do you put operations that don’t involve computation (such as logging, storing data, changing application state, etc.)?
Functional programming refers to operations that have nothing to do with the calculation of data as “side effects.”
A hook is a hook
React hooks are the React function component’s solution for introducing side effects to function components.
The body of a function component should only be used to return the HTML code of the component; all other operations (side effects) must be introduced via hooks.
React provides special hooks for many common operations (side effects) :
useState()
: Save stateuseContext()
: Save contextuseRef()
: Save reference- .
UseEffect () is a generic side effect hook. It can be used when no corresponding hook can be found.
Four, useEffect
import React, { useEffect } from 'react'; Function Welcome(props) {useEffect(() => {document.title = 'loading done '; }); return <h1>Hello, {props.name}</h1>; }Copy the code
In the example above, the argument to useEffect() is a function that is the desired side effect (changing the page title). React executes this function once the component is loaded.
1. UseEffect () is the second argument
function Welcome(props) {
useEffect(() => {
document.title = `Hello, ${props.name}`;
}, [props.name]);
return <h1>Hello, {props.name}</h1>;
}
Copy the code
The **componentDidUpdate()** method is used.
If the second argument is an empty array, then the side effect argument does not have any dependencies. Therefore, the side effects function is executed only once after the component is loaded into the DOM, and not again after the component is re-rendered. The **componentDidMount()** method.
2. Return value of useEffect()
Side effects occur as the component is loaded, and may need to be cleaned up when the component is unloaded.
UseEffect () allows you to return a function that is executed to clean up side effects when the component is unloaded.
useEffect(() => {
const subscription = props.source.subscribe();
return () => {
subscription.unsubscribe();
};
}, [props.source]);
Copy the code
In the example above, useEffect() subscribes to an event when the component is loaded and returns a cleanup function that unsubscribes when the component is unloaded. Function equivalent to **componentWillUnmount()** method.
3. Pay attention to the point
If there are multiple side effects, multiple useeffects () should be called rather than written together.
UseState () : state hook
const [state, setState] = React.useState(initialState);
Copy the code
Returns a state and a function to update the state.
The setState function is used to update state. It receives a new state value and queues a re-rendering of the component.
1. Functional updates
setState(i => i+1)
Copy the code
This form is preferred for multiple state operations
2. useState
Update objects are not merged automatically
We can use a functional setState in conjunction with the expansion operator to merge updated objects:
const [state, setState] = useState({}); SetState (prevState => {// Also use object. assign return {... prevState, ... updatedValues}; });Copy the code
3. Lazy initial state
The initialState parameter is only used in the initial rendering of the component and will be ignored in subsequent renderings. If the initial state needs to be computed through complex calculations, we can pass in a function that computes and returns the initial state, which is only called during the initial render:
const [state, setState] = useState(() => {
const initialState = someExpensiveComputation(props);
return initialState;
});
Copy the code
UseReducer () : Action hook
React itself does not provide state management, and external libraries are usually required. The most commonly used library for this is Redux.
The core concept of Redux is that components emit actions to communicate with the state manager. After the state manager receives the action, the Reducer function is used to calculate the newState. The Reducer function is in the form (state, action) => newState.
The useReducers() hook is used to introduce the Reducer function:
const [state, dispatch] = useReducer(reducer, initialState);
Copy the code
It is equivalent to a sophisticated version of useState. It receives a Reducer and returns the current state and its accompanying dispatch method.
UseReducer can be more useful than useState in some situations, such as when the state logic is complex and contains multiple subvalues, or when the next state depends on the previous state. Also, using useReducer can optimize performance for components that trigger deep updates because you can pass dispatches to child components instead of callbacks.
Here is an example of a counter. The Reducer function used to calculate the state is as follows:
const myReducer = (state, action) => {
switch(action.type) {
case('countUp'):
return {
...state,
count: state.count + 1
}
default:
return state;
}
}
Copy the code
The component code is as follows:
function App() {
const [state, dispatch] = useReducer(myReducer, { count: 0 });
return (
<div className="App">
<button onClick={() => dispatch({ type: 'countUp' })}>
+1
</button>
<p>Count: {state.count}</p>
</div>
);
}
Copy the code
Because Hooks can provide shared state and Reducer functions, they can replace Redux in these areas, as follows:
- Put the data together in one
store
object - Focus all operations on
reducer
- To create a
Context
- Create read and write apis for data
- Put the contents of step 4 in step 3
Context
- with
Context.Provider
willContext
Provided to all components - For each component
useContext
Get the read and write API
However, useReducer doesn’t provide middleware or time travel, so use Redux if you need them.
UseContext () : shared state hook
const value = useContext(MyContext);
Copy the code
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 < MyContext.provider > value prop of the upper-layer component closest to the current component.
If you need to share state between components, use useContext().
We now have two components, Navbar and Messages, and we want to share state between them:
<div className="App">
<Navbar/>
<Messages/>
</div>
Copy the code
The first step is to create a Context outside the component using the React Context API:
const AppContext = React.createContext({});
Copy the code
Component encapsulation code is as follows:
<AppContext.Provider value={{
username: 'superawesome'
}}>
<div className="App">
<Navbar/>
<Messages/>
</div>
</AppContext.Provider>
Copy the code
In the code above, AppContext.Provider provides a Context object that can be shared by quilt components.
The code for the Navbar component is as follows:
const Navbar = () => {
const { username } = useContext(AppContext);
return (
<div className="navbar">
<p>AwesomeSite</p>
<p>{username}</p>
</div>
);
}
Copy the code
Eight, useRef
const refContainer = useRef(initialValue);
Copy the code
UseRef returns a mutable ref object whose.current property is initialized as the passed parameter (initialValue). The ref object returned remains constant throughout the life of the component.
A common use case is to mandate access to child components:
function TextInputWithFocusButton() { const inputEl = useRef(null); Const onButtonClick = () => {// 'current' points to the text input element inputel.current.focus () mounted to the DOM; }; return ( <> <input ref={inputEl} type="text" /> <button onClick={onButtonClick}>Focus the input</button> </> ); }Copy the code
In essence, useRef is like a “box” that can hold a mutable value in its.current property.
Nine, useMemo
const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);
Copy the code
Returns an memoized value.
Passing the “create” function and an array of dependencies as arguments to useMemo, it recalculates memoized values only when a dependency changes, equivalent to computed in Vue 2. This optimization helps avoid costly calculations every time you render.
Functions passed into useMemo are executed during rendering. Please do not perform non-rendering operations inside this function. Operations such as side effects are used by useEffect, not useMemo.
If the dependency array is not provided, useMemo evaluates the new value each time it renders.
** You can use useMemo as a means of performance optimization, but don’t use it as a semantic guarantee. ** In the future React may choose to “forget” some of the previous Memoized values and recalculate them at the next render, such as freeing memory for off-screen components. Write code that can run without useMemo first — then add useMemo to your code to optimize performance.
X. Custom Hook
A custom Hook is a function whose name begins with “**use**” that can call other hooks from within the function.
Unlike the React component, custom hooks do not need to have a special identity. We are free to decide what its arguments are and what it should return (if necessary). In other words, it’s just like a normal function. But its name should always start with use, so it can be seen at a glance that it meets Hook rules.
More content