Hooks

Hooks are a new feature in Act 16.8 that allows you to use state and other features without writing classes.

motivation

  • Reusing state logic between components is difficult
  • Complex components become difficult to understand
  • incomprehensibleclass

HooksThe rules

  • Only used at the top levelHooksDo not reuse ‘in looping/conditional/nested functions
  • Only in theReactCall from a functionHooks

The difference between function components and class components

The function component can capture the values used for the current rendering.

Click to see examples

For a class component, although this is immutable, this is mutable. When we render the component, this changed, so this.props changed. So this. ShowMessage gets the latest props value.

For function components it captures the values used for rendering. This feature is also used on state when using hooks.

Click to see examples

const showMessage = () = > {
	alert("Write:" + message);
};

const handleSendClick = () = > {
	setTimeout(showMessage, 3000);
};

const handleMessageChange = (e) = > {
	setMessage(e.target.value);
};
Copy the code

If we want to get out of the ‘function component captures the value used for the current rendering’ feature, we can use ref to track some data. Current to get the latest value

const showMessage = () = > {
	alert("Write:" + ref.current);
};

const handleSendClick = () = > {
	setTimeout(showMessage, 3000);
};

const handleMessageChange = (e) = > {
	setMessage(e.target.value);
	ref.current = e.target.value;
};
Copy the code

useEffect

UseEffect can perform side effects (data fetch/involving subscriptions) in function components, UseEffect is a componentDidMount/componentDidUpdate/componentWillUnMount

  • The first argument is acallbackTo return todestory.destoryAs the next onecallbackCall before execution to clear the last timecallbackSide effects
  • The second argument is a dependency, an array that can have multiple dependencies. Dependency changes, perform the previous onecallbackThe returneddestory, and implement neweffectThe first parametercallback

For useEffect execution, the React processing logic is called asynchronously. The callback for each effect will be placed in the task queue like the setTimeout callback function, and will be executed after the main thread is completed. So the effect callback does not block the browser from drawing the view

  1. Associated lifecycle replacement schemes
  • ComponentDidMount Alternative
React.useEffect(() = >{
	// Request data, event listener, DOM manipulation}, [])//dep=[], only executed during initialization
UseEffect captures props and state, so even in the callback function we get the original props and state */
Copy the code
  • componentDidUnmountalternative
React.useEffect(() = >{
    /* Request data, event listener, manipulate DOM, add timer, delay timer */
    return function componentWillUnmount(){
        /* Remove event listener, clear timer, delay timer */
    }
},[])/* dep = [] */

UseEffect The return value of the first function can be used as componentWillUnmount
Copy the code
  • componentWillReceivePropsalternative

Actually both execution time is completely different, one in the render phase, a in the commit phase, initialization useEffect will perform a, but componentWillReceiveProps will only update when props change

React.useEffect(() = >{
    console.log('componentWillReceiveProps props changes:)
},[ props ])
Copy the code
  • componentDidUpdatealternative

UseEffect and componentDidUpdate are executed asynchronously, while componentDidUpdate is executed synchronously, but both are in the COMMIT phase

React.useEffect(() = >{
    console.log('Component update completed: componentDidUpdate')})// With no deP dependency and no second argument, this effect is executed every time the function component executes.
Copy the code
  1. inuseEffectWhat needs to be handled in []

React React

Only if the function (and the function it calls) doesn’t reference props, state, and the values derived from them can you safely omit them from the dependency list. Use eslint-plugin-react-hooks to help validate our code

Click for a detailed example

function Counter() {
  const [count, setCount] = useState(0);

  useEffect(() = > {
    const id = setInterval(() = > {
      setCount(count + 1);
    }, 1000);
    return () = > clearInterval(id); } []);return <h1>{count}</h1>;
}
// Only one update will be made, and then the timer will stop running
Copy the code
  1. Should I think of the function aseffectThe dependence of
const loadResourceCatalog = async() = > {if(! templateType)return
	const reqApi = templateType === TEMPLATE_TYPE.STANDARD ? 'listCatalog' : 'getCodeManageCatalog'
	const res: any = await API[reqApi]()
	if(! res.success)return
	setCatalog(res.data)
}

useEffect(() = > {
	loadResourceCatalog();
}, [])
The loadResourceCatalog function uses a state such as templateType
// During development, you might forget that the loadResourceCatalog function depends on the templateType value
Copy the code

The first simple solution, for some functions that are only used in useEffect, is to define effect directly so that you can rely directly on some states

useEffect(() = > {
	const loadResourceCatalog = async() = > {if(! templateType)return
		const reqApi = templateType === TEMPLATE_TYPE.STANDARD ? 'listCatalog' : 'getCodeManageCatalog'
		const res: any = await API[reqApi]()
		if(! res.success)return
		setCatalog(res.data)
	}
	loadResourceCatalog();
}, [templateType])
Copy the code

If we needed to use the function we defined in many places, couldn’t put the definition in the current effect, and put the function in a second dependent parameter, the code would go into an infinite loop. This is because the function returns a new reference on each render

const Template = () = > {
	const getStandardTemplateList = async() = > {const res: any = await API.getStandardTemplateList()
	  if(! res.success)return;
		const { data } = res;
		setCascaderOptions(data);
		getDefaultOption(data[0])
	}
	useEffect(() = >{
		getStandardTemplateList()
	}, [])
}
Copy the code

In this case, if the current function does not refer to any value within any component, it can be defined outside the component so that the function reference does not change again each time the component renders.

const getStandardTemplateList = async() = > {const res: any = await API.getStandardTemplateList()
  if(! res.success)return;
	const { data } = res;
	setCascaderOptions(data);
	getDefaultOption(data[0])}const Template = () = > {
	useEffect(() = >{
		getStandardTemplateList()
	}, [])
}
Copy the code

If the current function references some state values within the component, you can wrap the current function with useCallBack

const loadResourceCatalog = useCallback(async() = > {if(! templateType)return
	const reqApi = templateType === TEMPLATE_TYPE.STANDARD ? 'listCatalog' : 'getCodeManageCatalog'
	const res: any = await API[reqApi]()
	if(! res.success)return
	setCatalog(res.data)
}, [templateType])

useEffect(() = > {
	loadResourceCatalog();
}, [loadResourceCatalog])
// With the useCallback package, if templateType remains unchanged, loadResourceCatalog will also remain unchanged, so useEffect will not be rerun
// If templateType changes, loadResourceCatalog also changes, so useEffect is re-run
Copy the code

useCallback

React React

useCallback(fn, deps)

Returns a Memoized callback function that is updated only when a dependency changes

import React, { useCallback, useState } from "react";

const CallBackTest = () = > {
  const [count, setCount] = useState(0);
  const [total, setTotal] = useState(0);
  const handleCount = () = > setCount(count + 1);
  //const handleCount = useCallback(() => setCount(count + 1), [count]);
  const handleTotal = () = > setTotal(total + 1);

  return (
    <div>
      <div>Count is {count}</div>
      <div>Total is {total}</div>
      

      <div>
        <Child onClick={handleCount} label="Increment Count" />
        <Child onClick={handleTotal} label="Increment Total" />
      </div>
    </div>
  );
};

const Child = React.memo(({ onClick, label }) = > {
  console.log(`${label} Child Render`);
  return <button onClick={onClick}>{label}</button>;
});

export default CallBackTest;
Copy the code

Click for a detailed example

React.memo is a new property introduced in React16.6. The memo is a shallow comparison between the props and the next props to determine whether the current props are the same. If you’ve used the class component approach, then you know that memo is just like the React.PureComponent in the class component, except that memo is used in the function component. UseCallback and React. Memo must be used together to be effective.

Usage scenarios

  • As apropsTo avoid unnecessary rendering of child elementsReact.MemoUse, otherwise meaningless
  • As auseEffectYou only need to add them when you need to compare themuseCallback

useMemo

React React

Returns an memoized value

Memoized values are recalcitated only when a dependency changes. This optimization helps to avoid costly computations on every render. UseCallback (fn, DEps) is equivalent to useMemo(() => fn, deps). It’s basically similar to useCallback, but slightly different

Usage scenarios

  • Avoid costly calculations every time you render

Both hooks are built into React for a specific reason:

1. Reference equality

When you define an object in the React function component, it doesn’t refer to the same object as the last time it was defined (even though it has all the same values and properties).

  • Depend on the list
  • React.memo

Most of the time, you don’t need to worry about optimizing unnecessary re-renders because optimization always comes with a cost.

  1. Expensive calculation

A function that computes values synchronously at high cost

conclusion

This article introduces hooks generation motivation, the difference between function components and class components, useEffect/useCallback/useMemo, etc. The life cycle replacement scheme of useEffect and whether function is used as the second parameter of useEffect are introduced.

Refer to the link

When to useMemo and useCallback

How to fetch data with React Hooks

A Complete Guide to useEffect

How Are Function Components Different from Classes?

UseCallback, useMemo analysis & differences