0. Create react project
Now create a react project using the create react app, the official scaffold of react:
- Step 1: install scaffold NPM install - G create react app globally
- Step 2: switch to the directory where you want to create the project and use the command: create react app react_ project
- Step 3: switch the directory to the project: cd react_project
- Step 4: start the project: npm run start
1. Introduction to reacthooks
Hook is a new feature of React 16.8 (if react version is 16.8 or above, you don't need to download the hooks library, just refer to it directly). It allows you to use state and other react features without writing a class. Using ReactHooks can make our code concise and elegant.
Let's do a simple example: click the button to add 1 to the number
First, define the component in the way of class
import React, { Component } from 'react' export default class Example extends Component { constructor(props){ super(props) this.state = {count:0} } render() { return ( <div> <p>You clicked {this.state.count} times</p> <button onClick={this.addCount.bind(this)}>Click me</button> </div> ) } addCount(){ this.setState({count:this.state.count+1}) } }
Let's do it with React Hooks
import React, {useState} from 'react' const Example = () => { const [count,setCount] = useState(0) return( <div> <p>You clicked {count} times</p> <button onClick={()=>{setCount(count+1)}}>Click me</button> </div> ) } export default Example
Here are the effects:
2.useState
useState is a hook function of react, which is used to declare state variables. useState the parameter received by this function is the initial value of the state. It returns an array. Bit 0 of this array is the current state value, and bit 1 is the method that can change the state value.
Take another look at the code above:
import React, {useState} from 'react' const Example = () => { //1. Use useState to declare count variable and setCount function //Count is equivalent to a variable, and the initial value 0 is assigned to count //setCount is a function that changes our value const [count,setCount] = useState(0) //Array deconstruction. You may have to write three lines without array deconstruction return( <div> {/* 2.Read count variable */} <p>You clicked {count} times</p> {/* 3.Use the setCount function to change the value of our count */} <button onClick={()=>{setCount(count+1)}}>Click me</button> </div> ) } export default Example
3.useEffect
3.1.useEffect replaces the commonly used declared periodic function
There is a life cycle in class components, but there is no life cycle in function components. The use of useEffect can be used to replace our commonly used declaration cycle functions componentDidMount and componentDidUpdate. The counter results are printed on the browser console after the first rendering of the component and after each change in the counter state.
When using useEffect, you should pay attention to two points:
- The useEffect function will be called for the first rendering of React and every subsequent rendering. Before, we used two life cycle functions to represent the first rendering (componentDidMount) and the re rendering (componentDidUpdate) caused by update.
- The execution of the functions defined in useEffect will not hinder the browser update attempt, that is, these functions are executed asynchronously, while the code in componentDidMount and componentDidUpdate are executed synchronously. Personally, I think this has both advantages and disadvantages. For example, we need to draw the size of the current pop-up window according to the size of the page. If it is an asynchronous operation, it is not easy to operate.
Let's first show how to write class components
import React, {Component} from 'react' class Example extends Component{ constructor(props){ super(props) this.state = {count:0} } componentDidMount(){ console.log(`componentDidMount=>You clicked ${this.state.count} times`) } componentDidUpdate(){ console.log(`componentDidUpdate=>You clicked ${this.state.count} times`) } render(){ return( <div> <p>You clicked {this.state.count} times</p> <button onClick={this.addCount.bind(this)}>Click me</button> </div> ) } addCount(){ this.setState({count:this.state.count+1}) } } export default Example
Use useEffect
import React, {useState, useEffect} from 'react' const Example = () => { const [count,setCount] = useState(0) useEffect(() => { console.log(`useEffect => You clicked ${count} times`) }) return( <div> <p>You clicked {count} times</p> <button onClick={()=>{setCount(count+1)}}>Click me</button> </div> ) } export default Example
3.2. The useeffect implementation is similar to componentWillUnmount (executed when the component is about to be unloaded)
To use routing to unbind components, you need to use the return function in the useEffect function to replace the unbinding life cycle function. The componentWillUnmount component will be executed when it is about to be unloaded. However, there is a performance problem with using only the form of return function. It will execute the useEffect function once when the page changes, so we need to use the second parameter of useEffect at this time. See the following example for details.
Parent component:
import React, {useState, useEffect} from 'react' import {Index} from './index.js' import {List} from './list.js' //The usage of the following route is based on react router DOM version 6.0.1 and above import {BrowserRouter as Router,Routes, Route, Link} from 'react-router-dom' const Example = () => { const [count,setCount] = useState(0) useEffect(() => { console.log(`useEffect => You clicked ${count} times`) return () => { console.log('=============================') } },[count]) return( <Router> <div> <p>You clicked {count} times</p> <button onClick={()=>{setCount(count+1)}}>Click me</button> <ul> <li><Link to="/">home page</Link></li> <li><Link to="/list/">list</Link></li> </ul> <Routes> <Route path="/" exact element={<Index/>} /> <Route path="/list/" element={<List/>} /> </Routes> </div> </Router> ) } export default Example
index subcomponent:
import {useEffect} from 'react' export const Index = () => { //The second parameter of useEffect is an empty array //It means that the unbinding action can only be performed when the Index component is destroyed useEffect(() => { console.log('useEffect => index page') return () => { console.log('index The page is unbound') } },[]) return <h2>index page</h2> }
Sub component list:
import {useEffect} from 'react' export const List = () => { useEffect(() => { console.log('useEffect => List page') }) return <h2>list page</h2> }
The second parameter of useEffect is an array. Many variables corresponding to the state can be written in the array, which means that we unbind only when the state value changes. However, when an empty array is passed in, it is unbound only when the component is destroyed, which implements the life cycle function of componentWillUnmount.
4.useContext
useContext is mainly used to transfer values between parent and child components
Parent component
import React, {useState,createContext} from 'react' import {Counter} from './counter' export const CountContext = createContext() const Example = () => { const [count,setCount] = useState(0) //Array deconstruction. You may have to write three lines without array deconstruction return( <div> <p>You clicked {count} times</p> <button onClick={()=>{setCount(count+1)}}>Click me</button> <CountContext.Provider value={count}> <Counter/> </CountContext.Provider> </div> ) } export default Example
Sub component counter
import React, {useState,createContext} from 'react' import {Counter} from './counter' export const CountContext = createContext() const Example = () => { const [count,setCount] = useState(0) //Array deconstruction. You may have to write three lines without array deconstruction return( <div> <p>You clicked {count} times</p> <button onClick={()=>{setCount(count+1)}}>Click me</button> <CountContext.Provider value={count}> <Counter/> </CountContext.Provider> </div> ) } export default Example
5.useReducer
5.1 understanding what is reducer
The function reducer receives two parameters, one is the state, and the other is the judgment parameter used to control the business logic. The following uses Javascript to implement a reducer
//useReducer + useContext ~= Redux //Reducer originated in Redux, but it has nothing to do with redux //useReducer is a hooks function, which enhances the ordinary js reducer const countReducer = (state,action) => { switch(action.type){ case 'add': return state+1 case 'sub': return state-1 default: return state } }
5.2 using useReducer
import React, {useReducer} from 'react' const ReducerDemo = () => { const [count,dispatch] = useReducer((state,action)=>{ switch(action){ case 'add': return state+1 case 'sub': return state-1 default: return state } },0) return ( <div> <h2>Now the score is{count}</h2> <button onClick={()=>{dispatch('add')}}>Increment</button> <button onClick={()=>{dispatch('sub')}}>Decrement</button> </div> ) } export default ReducerDemo
5.3 implement useReducer useContext to realize state management and state sharing of redux
Realize the global status, unified management and unified distribution of events
Case: click the button to switch the corresponding font color
Parent component
//Combine useReducer and useContext to achieve the effect of Redux //useContext can be used to access the global state, avoiding layer by layer transmission, which is in line with the state globalization of redux //Using the action in useReducer, you can update the complex logical state and realize this part of reducer in redux // You can let vscode help us introduce components import React from 'react' import ShowArea from './showArea' import Buttons from './buttons' import {Color} from './color' const Example = () => { return ( <div> <Color> <ShowArea/> <Buttons/> </Color> </div> ) } export default Example
Font display area component
import React,{useContext} from 'react' import {ColorContext} from './color' const ShowArea = () => { const {color} = useContext(ColorContext) return (<div style={{color:color}}>Font color is{color}</div>) } export default ShowArea
Button assembly
import React,{useContext} from 'react' import {ColorContext,UPDATE_COLOR} from './color' const Buttons = () => { const {dispatch} = useContext(ColorContext) return ( <div> <button onClick={()=>{dispatch({type:UPDATE_COLOR,color:"red"})}}>gules</button> <button onClick={()=>{dispatch({type:UPDATE_COLOR,color:"yellow"})}}>yellow</button> </div> ) } export default Buttons
Color component
import React, {createContext,useReducer} from 'react' export const ColorContext = createContext({}) export const UPDATE_COLOR = "UPDATE_COLOR" const reducer = (state,action) => { switch(action.type){ case UPDATE_COLOR: return action.color default: return state } } export const Color = props => { const [color,dispatch] = useReducer(reducer,'blue') return ( <ColorContext.Provider value={{color,dispatch}}> {props.children} </ColorContext.Provider> ) }
6.useMemo
useMemo is mainly used to solve the performance problem of useless rendering generated by using React hooks. Functional components do not have shouldComponentUpdate (triggered before component update). We can't decide whether to update the component through the conditions before the component.
In addition, in the function component, the two states of mount and update are no longer distinguished, which means that every call of the function component will execute all internal logic, resulting in a very large performance loss. useMemo and useCallback solve the above performance problems.
Parent component:
//useEffect does not have the life cycle shouldComponetUpdate //For example: the status of the parent component has been updated, but the child component has not changed and does not need to be updated //However, using useEffect will update, so that the methods in the subcomponent have to be executed again //If the sub component is just a simple ui, it will greatly affect the performance if it needs to request data from the background import React ,{useState} from 'react' import Child from './child' const Example = () => { const [bingdwendwen,setBingdwendwen] = useState('Bing dwen dwen busy') const [xuerongrong,setXuerongrong] = useState('Shuey Rhon Rhon') return ( <div> <button onClick={()=>{setXuerongrong(new Date().getTime())}}>Shuey Rhon Rhon</button> <button onClick={()=>{setBingdwendwen(new Date().getTime()+'Bing dwen dwen towards us.')}}>Bing Dwen Dwen</button> <Child name={xuerongrong}> {bingdwendwen} </Child> </div> ) } export default Example
Sub components:
import {useMemo} from 'react' const Child = ({name,children}) => { const changeXuerongrong = (name) => { console.log('Shuey Rhon Rhon came to us.') return name + ',Shuey Rhon Rhon came to us.' } // const actionXuerongrong = changeXuerongrong(name) const actionXuerongrong = useMemo(()=> changeXuerongrong(name),[name]) //👇 It's wrong to add a brace // const actionXuerongrong = useMemo(()=> {changeXuerongrong(name)},[name]) return ( <div> <div>{actionXuerongrong}</div> <div>{children}</div> </div> ) } export default Child
7.useCallback
import React,{useState,useEffect,useCallback} from 'react' //Custom hooks function, which must start with use const useWinSize = () => { const [size,setSize] = useState({ width:document.documentElement.clientWidth, height:document.documentElement.clientHeight, }) const onResize = useCallback(() => { setSize({ width:document.documentElement.clientWidth, height:document.documentElement.clientHeight, }) }) useEffect(() => { window.addEventListener('resize',onResize) return ()=>{ window.removeEventListener('resize',onResize) } },[]) return size } const Example = () => { const size = useWinSize() return ( <div>page Size:{size.width}x{size.height}</div> ) } export default Example
8.useRef
- After you get any DOM element in jsreact, you can control it with jsref. However, this is generally not recommended. The change of React interface can be controlled by state.
- Using useRef to save variables can also be rarely used in work. We have useContext. In fact, such saving is of little significance
import React,{useEffect, useRef,useState} from 'react' const Example = () => { const inputE1 = useRef(null) const onButtonClick = () => { inputE1.current.value = "hello,bingdwendwen!" console.log(inputE1) } const [text,setText] = useState('bingdwendwen') const textRef = useRef() useEffect(()=>{ textRef.current = text console.log('textRef.current:',textRef.current) }) return ( <div> <input ref={inputE1} type="text" /> <button onClick={onButtonClick}>stay input Display text on</button> <br/> <input value={text} onChange={(e) => {setText(e.target.value)}}/> </div> ) } export default Example
9. Customize Hooks function
Example, since the first hooks function to monitor the browser window size in real time
Customize the hooks function. Remember to start with use
import React,{useState,useEffect,useCallback} from 'react' //Custom hooks function, which must start with use const useWinSize = () => { const [size,setSize] = useState({ width:document.documentElement.clientWidth, height:document.documentElement.clientHeight, }) const onResize = useCallback(() => { setSize({ width:document.documentElement.clientWidth, height:document.documentElement.clientHeight, }) }) useEffect(() => { window.addEventListener('resize',onResize) return ()=>{ window.removeEventListener('resize',onResize) } },[]) return size } const Example = () => { const size = useWinSize() return ( <div>page Size:{size.width}x{size.height}</div> ) } export default Example