One, foreword
I was twenty-one that day, and in the golden age of my life, I had so many hopes. I wanted to love, to eat, and to be in one moment a half-dark cloud in the sky. I felt that I could go on forever and nothing could hammer me.
Golden Age by Wang Xiaobo
B. Hooks
Hook is a new feature in React 16.8. It lets you use state and other React features without having to write a class. The essence of a Hook is still a JavaScript function, but there are two rules to follow when using it
Use hooks only at the top level
Never call hooks in loops, conditions, or nested functions. Be sure to always call them at the top of your React functions and before any returns.
Only the React function calls the Hook
Instead of calling a Hook in a normal JavaScript function, you can:
- Call a Hook in the React function component
- Call other hooks in custom hooks
Third, Hooks API
Hooks have the following apis, which are classified according to official documentation.
useState
The simplest hook function is to initialize a value, return the same state as initialState, and update the state function setState.
const [state, setState] = useState(initialState);
Copy the code
Let’s use useState
import React, { useState } from 'react';
const Index = () = > {
// setNumber updates the number function
const [number, setNumber] = useState(0);
return (
<>
<div>{number}</div>
<button onClick={()= > setNumber(number + 1)}>Add Number</button>
<button onClick={()= > setNumber(number - 1)}>Sub Number</button>
</>
);
};
export default Index;
Copy the code
We can see that useState initializes a value of number to zero and returns an array containing the number itself and the function setNumber that changes the number and we change the number by binding the setNumber with two buttons. Implement the value of number plus one minus one.
useEffect
UseEffect is used to emulate the lifecycle functions of class components in function components. Takes two arguments, the first of which is an arrow function. The arrow function returns a function that is triggered when the component is unloaded. (here’s an example 🌰 : when we want to listen to the message of the page, we can listen after the render DOM, and remove the listener when dom remove.)
About the second parameter [DEps]
- When there is no second argument, when
number
When changes occur, the component will render after remove, sort of likeshouldComponentUpdate
Life cycle. - When the second argument is [], only the initial render is executed, which is equivalent to the life cycle
componentDidMount
- When the second parameter is not null, only the parameters in the array are changed.
import React, { useEffect, useState } from 'react';
const Index = () = > {
// setNumber updates the number function
const [number, setNumber] = useState(0);
useEffect(() = > {
console.log('render dom');
return () = > {
console.log('dom remove');
};
}, [number]);
return (
<>
<div>{number}</div>
<button onClick={()= > setNumber(number + 1)}>Add Number</button>
<button onClick={()= > setNumber(number - 1)}>Sub Number</button>
</>
);
};
export default Index;
Copy the code
useContext
UseContext 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. In fact, useContext is similar to context.consumer. The use of context.consumer is mentioned here
<MyContext.Consumer>
{value= > {/* Render based on context value */}}
</MyContext.Consumer>
Copy the code
We use ThemeContext to receive a context object, using const Theme = useContext(ThemeContext); To subscribe to it, the theme value returned is the value prop of the closest < themecontext.provider value={themes.dark}> to the current component. So the theme rendered below is the dark theme.
import React, { useContext } from 'react';
const themes = {
light: {
foreground: '# 000000'.background: '#eeeeee',},dark: {
foreground: '#ffffff'.background: '# 222222',}};const ThemeContext = React.createContext();
function Index() {
return (
// Pass the light theme here
<ThemeContext.Provider value={themes.dark}>
<Toolbar />
</ThemeContext.Provider>
);
}
function Toolbar(props) {
return <ThemedButton />;
}
function ThemedButton() {
const theme = useContext(ThemeContext);
return (
<button style={{ background: theme.background.color: theme.foreground}} >
I am styled by theme context!
</button>
);
}
export default Index;
Copy the code
useReducer
UseReducer is an alternative to useState, which receives a reducer of the form (state, action) => newState (like redux). In some cases, useReducer is more useful than useState. For example, the state logic is complex and contains multiple subvalues. The following is an example of a counter that was rewritten using reducer in the useState section.
import React, { useReducer } from 'react';
function reducer(state, action) {
console.log(state, action);
switch (action.type) {
case 'add':
return { count: state.count + 1 };
case 'sub':
return { count: state.count - 1 };
default:
throw new Error();
}
}
function Index() {
// return 1
;
const [state, dispatch] = useReducer(reducer, { count: 0 });
return (
<>
<h1>count:{state.count}</h1>
<button onClick={()= > dispatch({ type: 'add' })}>+</button>
<button onClick={()= > dispatch({ type: 'sub' })}>-</button>
</>
);
}
export default Index;
Copy the code
useCallback
UseCallback (fn, deps) is equivalent to useMemo(() => FN, deps). It can be seen that it is used for caching functions. The following are the optimization suggestions (marked with CR) put forward by my mentor in reviewcode.
const TreeDemo = () = > {
// when functions are props for subcomponents, use useCallback;
// const onSelect = (selectedKeys) => {
// console.log('selected', selectedKeys);
/ /};
// const onCheck = (checkedKeys) => {
// console.log('onCheck', checkedKeys);
/ /};
//reviewcode
const onSelect = useCallback(selectedKeys= > {
console.log('selected', selectedKeys);
});
const onCheck = useCallback(checkedKeys= > {
console.log('onCheck', checkedKeys);
});
// cr: The default value is controlled by state. If there is an external value, the external value is preferred
return (
<Tree
checkable// Expands the specified tree node by defaultdefaultExpandedKeys={['0-0', '0-0-0', '0-0 to 1']} // The tree node selected by defaultdefaultSelectedKeys={['0-0']} // The tree node of the checkbox is selected by defaultdefaultCheckedKeys={['0-0 to 1', '0-0-0 to 1']}
onSelect={onSelect}
onCheck={onCheck}
treeData={treeData}
/>
);
};
Copy the code
useMemo
UseMemo is used to cache data. For example, sum is a parameter that needs to be calculated. If we do not cache the memo, then we will recalculate sum when updating the rank. This optimization helps avoid costly calculations every time you render.
import React, { useMemo, useState } from 'react';
function Index() {
const [count, setCount] = useState(100);
const [rank, setRank] = useState(1);
let sum = useMemo(() = > {
console.log('calculate');
let sum = 0;
for (let i = 0; i <= count; i++) {
sum += i;
}
return sum;
}, [count]);
return (
<>
<h1>{rank}</h1>
<button onClick={()= > setRank(rank + 1)}>Add Rank</button>
<h5>{sum}</h5>
<button onClick={()= > setCount(count + 1)}>Add Count</button>
</>
);
}
export default Index;
Copy the code
useRef
UseRef is used to get element DOM nodes, and there are other methods
- Ref ={node => this.node = node}
- Use the React. CreateRef () API
import React, { useRef } from 'react';
function Index() {
const node = useRef(null);
const getNode = () = > {
// Prints the node
console.log(node.current);
};
return (
<div>{/* Notice the binding */}<h1 ref={node}>Node</h1>
<button onClick={()= > getNode()}>Get Node</button>
</div>
);
}
export default Index;
Copy the code
useImperativeHandle
UseImperativeHandle allows you to customize the instance value exposed to the parent component when using ref. Let’s look at a parent component calling the child’s Focus function
import React, { forwardRef, useImperativeHandle, useRef } from 'react';
function Input(props, ref) {
console.log(props, ref);
const inputRef = useRef(null);
useImperativeHandle(
ref,
() = > {
const handleFn = {
focus(){ inputRef.current.focus(); }};returnhandleFn; } []);return <input type='text' ref={inputRef} />;
}
const UseInput = forwardRef(Input);
function Index() {
const current = useRef(null);
// console.log(current);
const handleClick = () = > {
console.log(current);
const { focus } = current.current;
focus();
};
return (
<div>
<UseInput ref={current} />
<button onClick={handleClick}>Get focus</button>
</div>
);
}
export default Index;
Copy the code
In the example above, React passes the current of the
element as the second argument to the render Input of the react. forwardRef function. Input passes current to the first parameter ref of useImperativeHandle. Note: instead of passing current to
, we use inputRef to take the DOM instance of
and operate it in useImperativeHandle. Instead, useImperativeHandle is used to broker the operation. The useImperativeHandle exposes methods for our use.
useLayoutEffect
Its function signature is the same as useEffect, but it calls Effect synchronously after all DOM changes. You can use it to read DOM layouts and trigger rerenders synchronously. The update schedule inside useLayoutEffect is refreshed synchronously before the browser performs the drawing. This means that the useLayoutEffect callback is executed before the browser draws, so the useLayoutEffect callback code may prevent the browser from rendering.
import React, { useEffect, useLayoutEffect, useState } from 'react';
function Index() {
const [color, setColor] = useState(0);
useLayoutEffect(() = > {
console.log('render');
if (color === 0) {
setColor(color + 1);
}
}, [color]);
const colorStyle = {
color: color ? 'yellow' : 'red'};return (
<>
<div style={colorStyle}>color text {color}</div>
<button onClick={()= > setColor(0)}>Click</button>
</>
);
}
export default Index;
Copy the code
As we can see from the example, when the Click button is clicked, the view stays yellow because the useLayoutEffect callback blocks the browser rendering. It’s only after the callback is done, setColor(color + 1), that the browser renders and the view stays yellow. When we change useLayoutEffect to useEffect, The flash occurs when we quickly Click on the Click button, because useEffect does not block the browser rendering, and when we Click serColor(0), the view is updated to red. After the useEffect callback setColor(color + 1) is executed, it turns yellow again, so a flicker occurs.
useDebugValue
useDebugValue(value)
Copy the code
UseDebugValue can be used to display tags for custom hooks in the React developer tool
function useFriendStatus(friendID) {
const [isOnline, setIsOnline] = useState(null);
// ...
// Display the label next to the Hook in the developer tools
// e.g. "FriendStatus: Online"
useDebugValue(isOnline ? 'Online' : 'Offline');
return isOnline;
}
Copy the code
prompt
We do not recommend that you add debug values to every custom Hook. It is most valuable when it is part of a shared library.
useTransition
The API is in an experimental phase and will be updated later.