All consumers that are descendants of a Provider will re-render whenever the Provider’s value prop changes. The propagation from Provider to its descendant consumers (including .contextType and useContext) is not subject to the shouldComponentUpdate method, so the consumer is updated even when an ancestor component skips an update.
Context API is not for solve all state sharing problem. Think like Context provider change(even prevent update by shouldComponentUpdate) all consumer will re-render.
The defaultValue argument is only used when a component does not have a matching Provider above it in the tree. This can be helpful for testing components in isolation without wrapping them. Note: passing undefined as a Provider value does not cause consuming components to use defaultValue.
Ref
React.createRef() API introduced in React 16.3. If you are using an earlier release of React, we recommend using callback refs instead.
There are a few good use cases for refs:
Managing focus, text selection, or media playback.
classCustomTextInputextendsReact.Component{constructor(props){super(props);// create a ref to store the textInput DOM element
this.textInput=React.createRef();this.focusTextInput=this.focusTextInput.bind(this);}focusTextInput(){// Explicitly focus the text input using the raw DOM API
// Note: we're accessing "current" to get the DOM node
this.textInput.current.focus();}render(){// tell React that we want to associate the <input> ref
// with the `textInput` that we created in the constructor
return(<div><inputtype="text"ref={this.textInput}/><inputtype="button"value="Focus the text input"onClick={this.focusTextInput}/></div>);}}classAutoFocusTextInputextendsReact.Component{constructor(props){super(props);this.textInput=React.createRef();}componentDidMount(){this.textInput.current.focusTextInput();}render(){return<CustomTextInputref={this.textInput}/>;}}
Adding a Ref to a Functional Component
By default, you may not use the ref attribute on function components because they don’t have instances:
If you want to allow people to take a ref to your function component, you can use forwardRef (possibly in conjunction with useImperativeHandle), or you can convert the component to a class.
importReact,{useContext,useEffect}from'react';import{store}from'./ContextProvider.jsx';constContextConsumer=()=>{// get field that you pass in provider value
const{state,dispatch}=useContext(store);useEffect(()=>{dispatch({type:'setID',payload:'ID1'});});return<div>{state.ID}</div>;};exportdefaultContextConsumer;
useContext(MyContext) is equivalent to static contextType = MyContext in a class, or to <MyContext.Consumer>
But You still need a <MyContext.Provider> above in the tree to provide the value for this context.
Unlike Redux dispatch function doesn’t need to add in useEffect or useCallback dependence list since dispatch always be a same function
setState by useReducer
Usually we set a state by useState. But if the state is simple boolean,useReduceris the shortest way to create a state for toggle a boolean value
1
2
3
4
5
6
7
8
const[switch,toggleSwitch]=useReducer((state)=>!state,false);// switch is a boolean
// toggleSwitch is a function
<buttononClick={()=>{toggleSwitch()}}value={switch}/>// or add one. if you want.
const[num,addOne]=useReducer((state)=>state+1,0);
relation with useState,
Theoretically, useReducer is a more general useState hook.
1
2
// this is exactly same with useState.
const[state,setSate]=useReducer((state)=>state,initVal);
That is whydispatchalways be same. (setState always same in useState)
useRef
useRef() creates a plain JavaScript object. The only difference between useRef() and creating a {current: ...} object yourself is that useRef will give you the same ref object on every render.
useLayoutEffect
The only different between useLayoutEffect and useEffect is that the useLayoutEffect is synchronous. Just same as componentDidMount and componentDidUpdate.
useLayoutEffect()
render
useEffect()
useImperativeHandle
useImperativeHandle customizes the instance value that is exposed to parent components when using ref. It is rare to use.
This is use for handle using ref to access functional component.
The React.lazy function lets you render a dynamic import as a regular component.
Component only be loaded when it will be rendered
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
importReact,{Suspense}from'react';// These lazy imports should put the end of other import code
constOtherComponent=React.lazy(()=>import('./OtherComponent'));constAnotherComponent=React.lazy(()=>import('./AnotherComponent'));functionMyComponent(){return(<div><Suspensefallback={<div>Loading...</div>}><section><OtherComponent/><AnotherComponent/></section></Suspense></div>);}
Tip
These lazy imports should put the end of other import code
You can even wrap multiple lazy components with a singleSuspense component.
Class Component vs Functional Component
Class Component lifecycle ==> Functional Component hooks
Class component
Functional component
state + setState
useState()
componentDidMount()
useEffect() with a empty input list
componentDidUpdate()
useEffect() with a input list contained which you want to change
componentWillUnmount()
useEffect() with a return callback function
shouldComponentUpdate()
export default React.memo()
Logic extraction
Suppose we have two components A and B that B is depends on A, the common solution is wrapping B in A. However,
when the logic in A need to reuse, we cannot copy and parse A to everywhere. Extracting the logic is essential.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
constA=()=>{// some logic will reuse
return(<div>// ... other component
<B_depends_on_A/></div>);};// render <A/>
constApp=()=>{return<A/>;};
NOTE
There are THREE method in React to reuse component logic: High-Order Component, Render Props, Customize Hook(function component ONLY)
This Blog is an example to extract logic by Three different way: Check this Blog
High-Order Component
Concretely, a higher-order component is a function that takes a component and returns a new component.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
constwithA=(ComponentB)=>{return(props)=>{// some logic will reuse
return(<div>// ... other component
<ComponentB{...props}/></div>);};};constBWithA=withA(<B/>);constApp=()=>{return<BWithAargs={...}>;};
Render props
Concretely, a render prop is a function prop that a component uses to know what to render.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
constA=({render})=>{// some logic will reuse
const[state,setState]=useState(1);return(<div>// ... other component
{render(state)}</div>);};constApp=()=>{return<Arender={(args)=><Bargs={args}/>}/>;};
Customize Hooks
Concretely, A custom Hook is a JavaScript function whose name starts with ”use” and that may call other Hooks.
1
2
3
4
5
6
7
8
9
constuseA=()=>{// some logic calculation
return[reuseLogicResult];};constApp=()=>{const[reuseLogicRes]=useA()return<Bargs={reuseLogicRes}/>}/>;};
Common Pitfall
Performance difference (SnapShot vs Current value)
When React introduce hooks for functional component, closure problem will be brought in as well. This will cause different performance between class component and function component with same logic.
importReact,{useState}from'react';importReactDOMfrom'react-dom';exportclassClassProfilePageextendsReact.Component{showMessage=()=>{alert('Followed '+this.props.user);};handleClick=()=>{setTimeout(this.showMessage,3000);};render(){return(<buttononClick={this.handleClick}>GetCurrentvalue(classcomponent)</button>);}}exportfunctionFunctionProfilePage(props){constshowMessage=()=>{alert('Followed '+props.user);};consthandleClick=()=>{setTimeout(showMessage,3000);};return(<buttononClick={handleClick}>GetSnapshot(functionalcomponent)</button>);}functionApp(){const[state,setState]=useState(1);return(<divclassName="App"><buttononClick={()=>{setState((x)=>x+x);}}>double</button><div>state:{state}</div>{/* snapshot */}<FunctionProfilePageuser={state}/>{/* current value */}<ClassProfilePageuser={state}/></div>);}
In React, Because props is immutable(assign a new obj when you want to change it) in functional component, each rendering has different props. Every click will generate a new props and setTimeout() display the value when you click. However, in Class component. After class generated, props is associated with class itself. Every rendering in class component have same this.props and this.props.user change overtime. Therefore, setTimeout() use same this.props and access this.props.user which is current value.