play React Hooks
in the above, we talked about using useMemo
to handle extraneous rendering. Next, let's take a look at the magic use of these hooks of React Hooks
(it is recommended to be familiar with and use the corresponding React Hooks
before you can make a good hook)
useMemo
when a child component is called in a parent component, the state of the parent component changes, causing the parent component to update, while the child component is updated even though it has not changed.
to put it simply, when the content of a page is very complex and there are many modules, functional components will be updated from beginning to end . As long as there is a change, all modules will be refreshed, which is obviously not necessary.
our ideal state is that each module only updates itself and does not influence each other, so using useMemo
is the best solution at this time.
pay particular attention here. as long as the status of the parent component is updated, the child component will update regardless of whether the self-component is operated or not . useMemo
is to prevent this
before we talk about useMemo
, let's talk about memo
, memo
. The function of combines the pure components of pureComponent and the function of componentShouldUpdate . It compares the passed props, and then further determines which props needs to be updated according to the return value of the second function. (specific use will be discussed below)
The concept of
useMemo
is similar to that of memo
. It determines whether the callback
function is executed by judging whether the current qualification is met, while the second parameter of useMemo
is an array that determines whether to update the drop function
this method can be used in elements, components, and context , especially in arrays. Let's first look at an example:
useMemo(() => (
<div>
{
list.map((item, index) => (
<p key={index}>
{item.name}
</>
)}
}
</div>
),[list])
undefined
from the above we can see that useMemo
renders only when list
changes, thus reducing unnecessary overhead
summarize the benefits of useMemo
:
- can reduce unnecessary loops and unnecessary rendering
- can reduce the number of rendering times for sub-components
- updates through special dependencies can avoid a lot of unnecessary overhead, but it should be noted that sometimes you cannot get the latest value with
useState
. In this case, you can consider usinguseRef
to solve
.
useCallback
useCallback
is very similar to useMemo
, except that useMemo
returns the result of the function , while useCallback
returns function
Note: this function is a function of the parent component passing child components to prevent irrelevant refreshes. Secondly, this component must cooperate with memo
, otherwise will not improve performance, but may also degrade performance
import React, { useState, useCallback } from 'react';
import { Button } from 'antd-mobile';
const MockMemo: React.FC<any> = () => {
const [count,setCount] = useState(0)
const [show,setShow] = useState(true)
const add = useCallback(()=>{
setCount(count + 1)
},[count])
return (
<div>
<div style={{display: 'flex', justifyContent: 'flex-start'}}>
<TestButton title="Normal click" onClick={() => setCount(count + 1) }/>
<TestButton title="UseCallback Click" onClick={add}/>
</div>
<div style={{marginTop: 20}}>count: {count}</div>
<Button onClick={() => {setShow(!show)}}> changing-over</Button>
</div>
)
}
const TestButton = React.memo((props:any)=>{
console.log(props.title)
return <Button color='primary' onClick={props.onClick} style={props.title === 'UseCallback Click' ? {
marginLeft: 20
} : undefined}>{props.title}</Button>
})
export default MockMemo;
undefined
We can see that when the switch button is clicked, the functions that are not encapsulated by useCallback
will be refreshed again, while the functions wrapped by useCallback
will not be refreshed again
useRef
useRef can get all the attributes of the current element and return a mutable ref object, and this object has only the current attribute , which can be set initialValue
get the corresponding attribute value through useRef
Let's look at a case first:
import React, { useState, useRef } from 'react';
const Index:React.FC<any> = () => {
const scrollRef = useRef<any>(null);
const [clientHeight, setClientHeight ] = useState<number>(0)
const [scrollTop, setScrollTop ] = useState<number>(0)
const [scrollHeight, setScrollHeight ] = useState<number>(0)
const onScroll = () => {
if(scrollRef?.current){
let clientHeight = scrollRef?.current.clientHeight; //Height of visible area
let scrollTop = scrollRef?.current.scrollTop; //Scroll bar scroll height
let scrollHeight = scrollRef?.current.scrollHeight; //Scrolling content height
setClientHeight(clientHeight)
setScrollTop(scrollTop)
setScrollHeight(scrollHeight)
}
}
return (
<div >
<div >
<p>Height of visible area:{clientHeight}</p>
<p>Scroll bar scroll height:{scrollTop}</p>
<p>Scrolling content height:{scrollHeight}</p>
</div>
<div style={{height: 200, overflowY: 'auto'}} ref={scrollRef} onScroll={onScroll} >
<div style={{height: 2000}}></div>
</div>
</div>
);
};
export default Index;
undefined
from the above, we can do some operations by useRef
to obtain the relevant attributes of the corresponding element.
cached data
in addition to getting the corresponding attribute values, useRef
has another important feature: caching data
mentioned above, when we encapsulate a qualified custom hooks
, we need to combine useMemo , useCallback and other Api, but we control the value of variables using useState may lead to get the old value, and if they update will cause the entire component to re-execute, in this case, we use useRef will be a very good choice
in the source code of react-redux
, after the introduction of hooks, react-redux
uses a large number of useMemo to redo Provide and other core modules, in which useRef is used to cache data, and none of the useRef () is bound to dom elements, they are all used for data caching
you can simply take a look:
// Cache Data
/* React redux uses userRef to cache the props after the merge*/
const lastChildProps = useRef()
const lastWrapperProps = useRef(wrapperProps)
//Whether to update props or not is in the updating state
const renderIsScheduled = useRef(false)
//Update data
function captureWrapperProps(
lastWrapperProps,
lastChildProps,
renderIsScheduled,
wrapperProps,
actualChildProps,
childPropsFromStoreUpdate,
notifyNestedSubs
) {
lastWrapperProps.current = wrapperProps
lastChildProps.current = actualChildProps
renderIsScheduled.current = false
}
undefined
We see that react-redux
changes the cached data source and reduces unnecessary updates by re-assigning values. If we adopt useState
, it is bound to render again
useLatest
through the above explanation, we know that useRef
can get the latest value, and we can simply encapsulate it. The advantage of this is that can ensure that the latest value is obtained at any time, and it can also solve the closure problem
import { useRef } from 'react';
const useLatest = <T>(value: T) => {
const ref = useRef(value)
ref.current = value
return ref
};
export default useLatest;
undefined