React system learning notes

Posted by Quilmes on Tue, 21 Dec 2021 06:49:57 +0100

React system learning notes

Ⅰ - basic knowledge and concept of React

Compared with vue, React has higher learning cost, or needs more basic knowledge, and needs some preliminary knowledge support

  1. webpack related knowledge
  2. axios related knowledge
  3. js foundation and es6 related knowledge

1, About React

  1. Official website link: Chinese official website
  2. Introduction description
  3. JavaScript for dynamically building user interfaces (focusing only on views)
  4. Open source by Facebook

1. Characteristics of React

  1. Declarative programming

  2. Component programming

  3. React Native writes native applications

React Native (RN) is a cross platform mobile application development framework opened by Facebook in April 2015. It is a derivative of the JS framework react, which was opened by Facebook earlier, on the native mobile application platform

  1. Efficient (excellent Diffing algorithm)

2. Why React is efficient

  1. With virtual DOM, you DON't always directly manipulate the real DON of the page
  2. DOM Diffing algorithm to minimize page redrawing
  3. Note: React does not improve the rendering speed, but may increase the rendering time. The reason for its real efficiency is that it can effectively reduce the number of rendering times

3. There are two ways to create a virtual DOM

I - js create virtual DOM (not recommended)

//1. Create a virtual DOM and create a nested doms
const VDOM=React.createElement('h1',{id:'title'},React.createElement('span',{},'hello,React'))
//2. Render virtual DOM to page
ReactDOM.render(VDOM,docoment.getElementById('test'))

II -jsx creating virtual DOM

//1. Create virtual DOM
	const VDOM = (  /* You must not write quotation marks here, because it is not a string */
    	<h1 id="title">
			<span>Hello,React</span>
		</h1>
	)
//2. Render virtual DOM to page
	ReactDOM.render(VDOM,document.getElementById('test'))

//3. Print the real DOM and virtual DOM. This step is not necessary for jsx to create a virtual DOM. I just want to facilitate reference
	const TDOM = document.getElementById('demo')
    console.log('fictitious DOM',VDOM);
	console.log('real DOM',TDOM);

It can be seen that the upper and lower methods are obviously more in line with our habits. When multiple nesting occurs, the js creation method will cause us great trouble in programming

But jsx actually just helps us do a layer of compilation. When we finish writing jsx code, our code will eventually be compiled into js writing mode

4. About virtual DOM

  1. An Object of type Object (general Object) when it is intrinsic
  2. The virtual DOM is' light 'and the real DOM is' heavy', because the virtual DOM is used internally by React and does not require so many attributes on the real DOM (only those required by React)
  3. The virtual DOM will eventually be transformed into a real DOM by React and presented on the page

2, jsx syntax rules

JSX is a syntax extension of JavaScript and an embedded XML like syntax. It is often used in React architecture, but it is not limited to this It should be said that JSX is popular because of the React framework, but there are other implementations As long as you are strong enough, you can even implement it on a single chip microcomputer (of course, you have to write its implementation method by yourself)

1. Rules

  1. When defining a virtual DOM, do not write quotation marks
  2. Use {} when mixing JS expressions into tags
  3. The class name of the style specifies to use className instead of class
  4. The inline style should be written in the form of style={{key:value}} (double {} represents an object and single {} represents an expression)
  5. Only one tag (the entire virtual DOM is wrapped in an outer layer and only one container)
  6. The label must be closed
  7. Label initials

If it starts with a lowercase letter, the tag will be converted to an element with the same name in html. If there is no element with the same name corresponding to the tag in html, an error will be reported

If it starts with a capital letter, ract will render the corresponding component. If the component is not defined, an error will be reported

2. Distinguish between [js statement (code)] and [js expression]

  1. Expression: an expression will produce a value, which can be placed wherever a value is required

These are expressions

  1. a

  2. a+b

  3. demo(1)

  4. arr.map()

  5. function test(){}

  6. Statement: cannot be placed in a statement that creates a virtual dom

  7. if(){}

  8. for(){}

  9. switch(){}

3, Differences between two component definitions, understanding of components and modules

I - components defined in react

① Functional declaration component

Executed reactdom What happened after render (...)?

1.React parses the component label and finds the MyComponent component.

2. it is found that the component is defined by function, and then calls the function to convert the returned virtual DOM to real DOM and then appear in the page.

② Class components (the following examples refer to class components)

Executed reactdom What happened after render (...)?

​ 1.React parsed the component label and found the MyComponent component.

​ 2. It is found that the component is defined using a class, and then new comes out the instance of the class, and calls the render method on the prototype through the instance.

​ 3. Convert the virtual DOM returned by render into a real DOM, and then render it in the page.

Where is the render in the component?

On the prototype object of MyComponent for instance use.

Who is this in render in the component?

MyComponent instance object < = > MyComponent instance object.

Ⅱ - module and modularization

① Module
  1. Understanding: a js program that provides specific functions externally is generally a js file
  2. Why break it into modules: as business logic increases, code becomes more and more complex
  3. Function: reuse js, simplify the preparation of js and improve the operation efficiency of js
② Modularization

When the js of an application is written in modules, the application is a modular application

III - assembly and modularization

① Components
  1. Understanding: a collection of code and resources used to achieve local functional effects (html/css/js/img, etc.)

  2. Why use components: the functionality of an interface is complex

  3. Function: reuse coding, simplify project coding and improve operation efficiency

② Componentization

When an application is implemented in a multi-component manner, the application is a component-based application

4, React component oriented programming

  1. Debug using React developer tools

React Developer Tools

  1. be careful

a) Component names must be capitalized

b) A virtual DOM element can only have one root element

c) Virtual DOM elements must have an end tag < / >

  1. Basic flow of rendering class component labels

a) A component instance object is created inside react

b) Call render() to get the virtual DOM and parse it into a real DOM

c) Insert inside the specified page element

1. Three attributes of component 1:state

① Understand
  1. state is the most important attribute of the component object, and the value is the object (which can contain a combination of multiple keys: values)
  2. The component is called a state machine, which updates the corresponding page display by updating the state of the component (re rendering the component)
② Strong attention
  1. this in the render method in the component is the component instance object

  2. this is undefined in the component customization method. How to solve it?

a) Force binding this: through bind() of function object

b) Arrow function recommendation

  1. Status data cannot be modified or updated directly
③ Code example
I - bind() of normal function object
    //1. Create component
		class Weather extends React.Component{
			//How many times does the constructor call———— Once
			constructor(props){
				console.log('constructor');
				super(props)
				//Initialization status
				this.state = {isHot:false,wind:'breeze'}
				//To solve the problem of this pointing in changeWeather, you can also use it directly after calling
				this.changeWeather = this.changeWeather.bind(this)
			}
			//How many times does render call———— 1+n times 1 is the initialization time, and N is the number of status updates
			render(){
				console.log('render');
				//Read status
				const {isHot,wind} = this.state
				return <h1 onClick={this.changeWeather}>It's a fine day today{isHot ? 'scorching hot' : 'pleasantly cool'},{wind}</h1>
			}
			//How many times does changeWeather call———— Adjust it several times
			changeWeather(){
				//Where is changeWeather———— On the prototype object of Weather for instance use
				//Because changeWeather is a callback to onClick, it is not called through an instance, but directly
				//The method in the class has local strict mode on by default, so this in changeWeather is undefined
				console.log('changeWeather');
				//Get the original isHot value
				const isHot = this.state.isHot
				//Important note: the state must be updated through setState, and the update is a merge, not a replacement.
				this.setState({isHot:!isHot})
				console.log(this);

				//Serious note: the state cannot be changed directly. The following line is direct change!!!
				//this.state.isHot = !isHot / / this is the wrong way to write
			}
		}
		//2. Render component to page
		ReactDOM.render(<Weather/>,document.getElementById('test'))
Ⅱ - abbreviation: form of assignment statement + arrow function
	    //1. Create component
		class Weather extends React.Component{
			//Initialization status
			state = {isHot:false,wind:'breeze'}
			render(){
				const {isHot,wind} = this.state
				return <h1 onClick={this.changeWeather}>It's a fine day today{isHot ? 'scorching hot' : 'pleasantly cool'},{wind}</h1>
			}
			//Custom method - use the form of assignment statement + arrow function
			changeWeather = ()=>{
				const isHot = this.state.isHot
				this.setState({isHot:!isHot})
			}
		}
		//2. Render component to page
		ReactDOM.render(<Weather/>,document.getElementById('test'))

2. Three attributes of component 2:props

① Understand
  1. Each component object will have props (short for properties) attribute
  2. All properties of the component tag are saved in props
② Function
  1. Changing data is transferred from the outside to the inside of the component through tag attributes
  2. Note: do not modify props data inside the component
③ Code example:
Class I - props for components
	//Create component
		class Person extends React.Component{
			render(){
				// console.log(this);
				const {name,age,sex} = this.props
				return (
					<ul>
						<li>full name:{name}</li>
						<li>Gender:{sex}</li>
						<li>Age:{age+1}</li>
					</ul>
				)
			}
		}
		//Render component to page
		ReactDOM.render(<Person name="jerry" age={19}  sex="male"/>,document.getElementById('test1'))
		ReactDOM.render(<Person name="tom" age={18} sex="female"/>,document.getElementById('test2'))
		const p = {name:'Lao Liu',age:18,sex:'female'}
		// console.log('@',...p);
		// ReactDOM.render(<Person name={p.name} age={p.age} sex={p.sex}/>,document.getElementById('test3'))
        //The assignment deconstruction method is used here to make the code more concise
		ReactDOM.render(<Person {...p}/>,document.getElementById('test3'))
II - props for function components
//Create component
		function Person (props){
			const {name,age,sex} = props
			return (
					<ul>
						<li>full name:{name}</li>
						<li>Gender:{sex}</li>
						<li>Age:{age}</li>
					</ul>
				)
		}
//The restriction here can be replaced by typescript
		Person.propTypes = {
			name:PropTypes.string.isRequired, //name is required and is a string
			sex:PropTypes.string,//Limit sex to string
			age:PropTypes.number,//Limit age to numeric
		}

		//Specifies the default label attribute value
		Person.defaultProps = {
			sex:'male',//sex defaults to male
			age:18 //age defaults to 18
		}
		//Render component to page
		ReactDOM.render(<Person name="jerry"/>,document.getElementById('test1'))
	

3. Three attributes of component 3:refs

① Understand

Tags within components can define ref s to identify themselves

② Code example:
1. Ref in string form (not recommended, will be eliminated)
//Display the data in the left input box
	showData = ()=>{
		const {input1} = this.refs
		alert(input1.value)
	}
	//Display the data in the input box on the right
	showData2 = ()=>{
		const {input2} = this.refs
		alert(input2.value)
	}
	render(){
		return(
			<div>
				<input ref="input1" type="text" placeholder="Click the button to prompt data"/>&nbsp;
				<button onClick={this.showData}>Click the data on the left of my prompt</button>&nbsp;
				<input ref="input2" onBlur={this.showData2} type="text" placeholder="Lost focus prompt data"/>
			</div>
		)
	}
}
2. ref in callback form
/**The following this refers to the component instance. I directly this Input1 = C means to assign an value to input1 on the instance, and then print it directly by calling*/
//Display the data in the left input box
	showData = ()=>{
		const {input1} = this
		alert(input1.value)
	}
	//Display the data in the input box on the right
	showData2 = ()=>{
		const {input2} = this
		alert(input2.value)
	}
	render(){
		return(
			<div>
				<input ref={c => this.input1 = c } type="text" placeholder="Click the button to prompt data"/>&nbsp;
				<button onClick={this.showData}>Click the data on the left of my prompt</button>&nbsp;
				<input onBlur={this.showData2} ref={c => this.input2 = c } type="text" placeholder="Lost focus prompt data"/>&nbsp;
			</div>
		)
	}
}

3. createRef the most recommended way to create a ref container
/*React.createRef After calling, a container can be returned, which can store the nodes identified by ref. the container is "special for special personnel"*/
myRef = React.createRef()
myRef2 = React.createRef()
//Display the data in the left input box
showData = ()=>{
	alert(this.myRef.current.value);
}
//Display the data in the input box on the right
showData2 = ()=>{
	alert(this.myRef2.current.value);
}
render(){
	return(
		<div>
			<input ref={this.myRef} type="text" placeholder="Click the button to prompt data"/>&nbsp;
			<button onClick={this.showData}>Click the data on the left of my prompt</button>&nbsp;
			<input onBlur={this.showData2} ref={this.myRef2} type="text" placeholder="Lost focus prompt data"/>&nbsp;
		</div>
	)
}
}	

4. Event handling and form data collection

I - event handling

  1. Specify the event handler through the onXxx attribute (note case)

a)React uses customization (synthetic events, not native DOM events) -- for better compatibility

b) Events in react are handled through event delegation (delegated to the outermost element of the component) -- for more efficiency

  1. Via event Get the DOM element object of the event from target ----- don't overuse ref

Ⅱ - Classification of form components

Formally speaking, a controlled component is to add a value attribute to a form component; An uncontrolled component is a component that does not add a value attribute

1. Controlled components
state = {//Initialization status
	username:'', //user name
	password:'' //password
}

//Save user name to status
saveUsername = (event)=>{
	this.setState({username:event.target.value})
}

//Save password to status
savePassword = (event)=>{
	this.setState({password:event.target.value})
}

//Callback for form submission
handleSubmit = (event)=>{
	event.preventDefault() //Block form submission
	const {username,password} = this.state
	alert(`The user name you entered is: ${username},The password you entered is: ${password}`)
}

render(){
	return(
		<form onSubmit={this.handleSubmit}>
			user name:<input onChange={this.saveUsername} type="text" name="username"/>
			password:<input onChange={this.savePassword} type="password" name="password"/>
			<button>Sign in</button>
		</form>
	)
}
}
2. Uncontrolled components
handleSubmit = (event)=>{
		event.preventDefault() //Block form submission
		const {username,password} = this
		alert(`The user name you entered is: ${username.value},The password you entered is: ${password.value}`)
	}
	render(){
		return(
			<form onSubmit={this.handleSubmit}>
				user name:<input ref={c => this.username = c} type="text" name="username"/>
				password:<input ref={c => this.password = c} type="password" name="password"/>
				<button>Sign in</button>
			</form>
		)
	}
}

5. Higher order function and function coritization

① Higher order function:

If a function conforms to either of the following two specifications, the function is a higher-order function

  1. If the parameter accepted by A function is A function, then A can be called A higher-order function
  2. If the return value of A function call is still A function, then A can be called A higher-order function

Common high-order functions include Promise, setTimeout, arr.map(), and so on

② Coritization of functions

The function coding form for the final unified processing of this accepted parameter is realized by continuing to return the function through function call

function sum(a){ return (b)=>{return c=>{ return a+b+c} }}
③ The binding of events is implemented without function coritization

Use the callback function directly because it takes a function as the return value

<input onChange={event => this.saveFormData('username',event) } type="text" name="username"/>

5, Life cycle

  1. A component goes through some specific stages from creation to death
  2. The React component contains a series of hook functions (life cycle callback functions), which will be called at a specific time
  3. When defining components, we will do specific work in specific life cycle callback functions

1. React lifecycle (old)

Call sequence of hooks in each life cycle

  1. Initialization phase: by reactdom Render() trigger -- first render

    • constructor()

    • compinentWillMount()

    • render()

    • Componentdidmount() = = > common components will be rendered

    Generally, initialization is done in this hook, such as starting the timer, sending network requests, subscribing to messages, etc

  2. Update phase: it is determined by this Setstate() or render trigger of parent component

    • shouldComponentUpdate() component should be updated
    • componentWillUpdate() component is about to be updated
    • Render() = = = > must use a
    • componentDidUpdate() component is about to be updated
  3. Uninstall components: by reactdom Triggered by unmountcomponentatnode

    • Componentwillunmount() = = = > common components will be uninstalled

    Generally, do some first things in this hook, such as turning off the timer, canceling subscription, etc

2. React lifecycle (New)

  1. Initialization phase: by reactdom Render() trigger - first render

    • constructor()
    • getDerivedStateFromProps() get derived state from Props
    • render()
    • Componentdidmount() = = = > common
  2. Update phase: it is determined by this Setstate() or render trigger of parent component

    • getDerivedStateFromProps() get derived state from Props
    • shouldComponentUpdate() component should be updated
    • render()
    • getSnapshotBeforeUpdate() takes a snapshot before updating
    • componentDidUpdate()
  3. Uninstall components: by reactdom Unmountcomponentatnode() trigger

    • Componentwillunmount() = = = > common

    Generally, you can do some closing things in this hook, such as closing the timer and unsubscribing messages

3. Important hook

  1. render: call to initialize rendering or update rendering
  2. componentDidMount(): enable listening and send ajax requests
  3. componentWillUnmount(): do some finishing work, such as cleaning up the timer

4. Hook to be discarded

  1. componentWillMount
  2. componentWillReceiveProps
  3. componentWillUpdate

ps: a warning will appear when you use it now. UNSAFE may need to be added in later versions_ Prefix can only be used. It may be completely discarded in the future. It is not recommended

It is speculated that the React team believes that increasing the use cost will indirectly affect us and let us adapt to the new hook, so this is added

6, key in react/vue

Classic interview questions:

1). What is the role of the key in react / Vue? (what is the internal principle of key?)

2). Why is it better not to use index for key when traversing the list?

① Role of key in virtual DOM:
  1. To put it simply: key is the identifier of the virtual DOM object and plays an extremely important role in updating the display

  2. In detail: when the data in the state changes, React will generate a new virtual DOM according to the new data, and then React will compare the diff of the new virtual DOM with the old virtual dom. The comparison rules are as follows:

  3. The same key as the new virtual DOM was found in the old virtual DOM:

    a) If the content in the virtual DOM does not change, use the previous real DOM directly

    b) If the content in the virtual DON changes, a new real DOM is generated, and then the previous real DOM in the page is replaced

  4. The same key as the new virtual DOM was not found in the old virtual dom

    Create a new real DOM from the data and then render it to the page

② Possible problems caused by using index as key:
  1. If you add or delete data in reverse order:

Unnecessary real DOM updates will be generated = = > the interface effect is no problem, but the efficiency is low

  1. If the structure also contains the DOM of the input class:

An error will be generated. DOM update = = > there is a problem with the interface

  1. be careful:

If there are no destructive operations such as adding or deleting data in reverse order, it is only used to render the list for display, and there is no problem using index as the key

③ How to select a key in development?
  1. It is better to use the unique identifier of each data as key, such as id, mobile phone number, id number, student number, etc.
  2. If you are sure that it is just a simple poem, you can use index
//Slow motion playback -- use the index value as the key
		Initial data:
				{id:1,name:'Xiao Zhang',age:18},
				{id:2,name:'petty thief',age:19},
		Initial virtual DOM: 
				<li key=0>Xiao Zhang---18<input type="text"/></li>
				<li key=1>petty thief---19<input type="text"/></li>

		Updated data:
				{id:3,name:'Xiao Wang',age:20},
				{id:1,name:'Xiao Zhang',age:18},
				{id:2,name:'petty thief',age:19},
		Virtual after updating data DOM: 
				<li key=0>Xiao Wang---20<input type="text"/></li>
				<li key=1>Xiao Zhang---18<input type="text"/></li>
				<li key=2>petty thief---19<input type="text"/></li>

-----------------------------------------------------------------

//Slow motion playback: use id unique id as key

		Initial data:
				{id:1,name:'Xiao Zhang',age:18},
				{id:2,name:'petty thief',age:19},
		Initial virtual DOM: 
				<li key=1>Xiao Zhang---18<input type="text"/></li>
				<li key=2>petty thief---19<input type="text"/></li>

		Updated data:
				{id:3,name:'Xiao Wang',age:20},
				{id:1,name:'Xiao Zhang',age:18},
				{id:2,name:'petty thief',age:19},
		Virtual after updating data DOM: 
				<li key=3>Xiao Wang---20<input type="text"/></li>
				<li key=1>Xiao Zhang---18<input type="text"/></li>
				<li key=2>petty thief---19<input type="text"/></li>

II - React scaffold

  1. xxx scaffold: used to help the original program quickly create a template project based on xxx library

a) Contains all required configurations (syntax check, jsx compilation, devServer...)

b) Download all related dependencies

c) You can run a simple effect directly

  1. React provides a scaffolding library for creating react projects: create react app

  2. The overall technical architecture of the project is: react+webpack+es6+eslint

  3. Characteristics of projects developed using scaffolding: modularization, componentization and engineering

webpack related knowledge points are needed here. I'll learn related knowledge first (2-3 nights)

1. Create project and start

  1. Global installation: NPM I - G create react app

  2. Switch to the directory where you want to create the project and use the command: create react arr Hello react

  3. Enter project folder

  4. Start project: npm start

2. react scaffold project structure

public -- static resource folder

​ favicon.icon ---- website tab Icon

​ index.html - main page

​ logo192. Png ---- logo diagram

​ logo512. Png ---- logo diagram

​ manifest.json ---- application shell configuration file

​ robots.txt ---- crawler protocol file

src -- source folder

​ App. CSS ---------- style of APP component

​ App. JS ----------- app * * * * component

​ App.test.js -- used to test app

​ index.css ------ style

​ index.js ------- entry file

​ logo. Svg ---- logo diagram

​ reportWebVitals.js

- page performance analysis file (supported by web vitals Library)

​ setupTests.js

---- files for component unit tests (supported by jest DOM Library)

3. Component coding process of functional interface

  1. Split component: split interface, extract components

  2. Implement static components: use components to achieve static page effects

  3. Implement dynamic components

3.1 dynamic display of initialization data

​ 3.1. 1 data type

​ 3.1. 2 data name

​ 3.1. 2. Which component is saved in?

3.2 interaction (starting from binding event listening)

4. TodoList partial code

1. When updating, you can update the data in the way that the repeated fields will be automatically overwritten after the assignment is deconstructed

​ -->if(todoObj.id === id) return {...todoObj,done}

2. Batch deletion of arrays can be realized by filter

//updateTodo is used to update a todo object
updateTodo = (id,done)=>{
		//Get todos in status
		const {todos} = this.state
		//Match processing data
		const newTodos = todos.map((todoObj)=>{
			if(todoObj.id === id) return {...todoObj,done}
			else return todoObj
		})
		this.setState({todos:newTodos})
	}

	//deleteTodo is used to delete a todo object
	deleteTodo = (id)=>{
		//Get the original todos
		const {todos} = this.state
		//Deletes the todo object with the specified id
		const newTodos = todos.filter((todoObj)=>{
			return todoObj.id !== id
		})
		//Update status
		this.setState({todos:newTodos})
	}

	//checkAllTodo is used to select all
	checkAllTodo = (done)=>{
		//Get the original todos
		const {todos} = this.state
		//Processing data
		const newTodos = todos.map((todoObj)=>{
			return {...todoObj,done}
		})
		//Update status
		this.setState({todos:newTodos})
}

Ⅲ-React ajax

This part needs to prepare the technical stack: ajax and Axios. Relevant notes have been recorded in the next folder and learning is completed

1. Configure proxy in React

  1. Simple proxy: in package JSON, add the following configuration: "proxy":http://localhost:5000
    • ps: when you ask http://localhost:5000 Add this code when generating cross domain (itself at port 3000), and then use it when you request http://localhost:3000 Make a request. When it cannot find a resource in port 3000, it will be automatically forwarded to port 5000 for a request without cross domain problems
    • Advantages: the configuration is simple, and the front end can request resources without any prefix.
    • Disadvantages: multiple agents cannot be configured
    • Working mode: configure the agent in the above way. When 3000 nonexistent resources are requested, the request will be forwarded to 5000 (matching the front-end resources first)
  2. Method 2: create a configuration file under src: src / setupproxy js
    • ps: it must be this file name. When the react project runs, it will automatically find this file and add it to the configuration of webpack. Therefore, after you modify this file, you need to restart the project
    • Advantages: multiple agents can be configured to flexibly control whether requests go through agents.
    • Disadvantages: the configuration is cumbersome, and the front end must add a prefix when requesting resources.
//Code example
const proxy = require('http-proxy-middleware')
 module.exports = function(app) {
   app.use(
     proxy('/api1', {  //api1 is the request to be forwarded (all requests with / api1 prefix will be forwarded to 5000)
       target: 'http://localhost:5000 ', / / configure the forwarding destination address (the server address that can return data)
       changeOrigin: true, //Controls the value of the host field in the request header received by the server
       /*
       	changeOrigin When set to true, the host in the request header received by the server is: localhost:5000
       	changeOrigin When set to false, the host in the request header received by the server is: localhost:3000
       	changeOrigin The default value is false, but we generally set the changeOrigin value to true
       */
       pathRewrite: {'^/api1': ''} //Remove the request prefix and ensure that the normal request address is given to the background server (must be configured)
     }),
     proxy('/api2', { 
       target: 'http://localhost:5001',
       changeOrigin: true,
       pathRewrite: {'^/api2': ''}
     })
   )
}

2. Supplementary knowledge points

Ⅰ - ES6 small knowledge points: continuous assignment, deconstruction + renaming

let obj = {a:{b:1}}
const {a} = obj; //Traditional deconstruction assignment
const {a:{b}} = obj; //Continuous deconstruction assignment
const {a:{b:value}} = obj; //Continuous deconstruction assignment + rename

Ⅱ - message subscription and publishing mechanism - > tool library: PubSubJS

1. Subscribe first and then publish (Understanding: it feels like an empty dialogue)

2. Applicable to communication between any components

3. Unsubscribe in componentWillUnmount of the component

//Download: NPM install PubSub JS -- save
//Use examples
1)	import PubSub from 'pubsub-js' //introduce
2)	PubSub.subscribe('delete', function(data){ }); //subscribe
3)	PubSub.publish('delete', data) //Release news
//*------------------------------Use----------------------------------------------------
	componentDidMount(){
		this.token = PubSub.subscribe('atguigu',(_,stateObj)=>{
			this.setState(stateObj)
		})
	}

	componentWillUnmount(){
		PubSub.unsubscribe(this.token)
	}
//----------------------------------Use---------------------------------------------------
		//Notify List of update status before sending request
		PubSub.publish('atguigu',{isFirst:false,isLoading:true})
		//Send network request --- send using fetch (optimized)
		try {
			const response= await fetch(`/api1/search/users2?q=${keyWord}`)
			const data = await response.json()
			console.log(data);
			PubSub.publish('atguigu',{isLoading:false,users:data.items})
		} catch (error) {
			console.log('Request error',error);
			PubSub.publish('atguigu',{isLoading:false,err:error.message})
		}
	}

III - message subscription and publishing mechanism - > tool library: MIT

This is what I later found in githyb and applied in the project code. The amount of code in this tool library is very small. You can read the source code, which will be of great benefit

This method is implemented with [MIT]. In fact, it essentially registers a global variable for listening -- > MIT source address

You can implement it yourself. Here, because others write well, take this as an example

  1. Install or copy directly
npm install --save mitt
  1. Use example
//
-------------- First define a common global variable  --------------------------
//File utils / index ts
import mitt from './mitt';
//Declare it here and make it a global variable
const eventBus = mitt();
export { eventBus }
---------------- Components that send values(To modify someone else's component)  ---------------------
//Import common variables
import { eventBus } from '~/utils';
  <a
  onClick={() => {
	//Delayed sending means that I have a jump action before this and jump to the receiver component
    // When the value is modified, but the receiving component is not registered, it can be sent directly under normal conditions     
    //setTimeout(() => {
    // eventBus.emit('foo', data);
    //}, 100);
    eventBus.emit('foo', data);    
   }}
  />;

------------------ Receiver component(Accept sender's component)  -------------------------------------

const Search: FC<IProps> = (props) => {
  useEffect(() => {
    //Replace with mitt writing method. At this time, it has been received
    eventBus.on('foo', (searchParams) => {console.log('Value accepted',searchParams) }
    });
  }, []);
} 
  1. MIT source code
export type EventType = string | symbol;

// An event handler can take an optional event argument
// and should not return a value
export type Handler<T = unknown> = (event: T) => void;
export type WildcardHandler<T = Record<string, unknown>> = (
  type: keyof T,
  event: T[keyof T]
) => void;

// An array of all currently registered event handlers for a type
export type EventHandlerList<T = unknown> = Array<Handler<T>>;
export type WildCardEventHandlerList<T = Record<string, unknown>> = Array<
  WildcardHandler<T>
>;

// A map of event types and their corresponding event handlers.
export type EventHandlerMap<Events extends Record<EventType, unknown>> = Map<
  keyof Events | '*',
  EventHandlerList<Events[keyof Events]> | WildCardEventHandlerList<Events>
>;

export interface Emitter<Events extends Record<EventType, unknown>> {
  all: EventHandlerMap<Events>;

  on: (<Key extends keyof Events>(type: Key, handler: Handler<Events[Key]>) => void) & ((type: '*', handler: WildcardHandler<Events>) => void);

  off: (<Key extends keyof Events>(
    type: Key,
    handler?: Handler<Events[Key]>
  ) => void) & ((type: '*', handler: WildcardHandler<Events>) => void);

  emit: (<Key extends keyof Events>(type: Key, event: Events[Key]) => void) & (<Key extends keyof Events>(
    type: undefined extends Events[Key] ? Key : never
  ) => void);
}

/**
 * Mitt: Tiny (~200b) functional event emitter / pubsub.
 * @name mitt
 * @returns {Mitt}
 */
export default function mitt<Events extends Record<EventType, unknown>>(
  all?: EventHandlerMap<Events>
): Emitter<Events> {
  type GenericEventHandler =
    | Handler<Events[keyof Events]>
    | WildcardHandler<Events>;
  all = all || new Map();

  return {
    /**
     * A Map of event names to registered handler functions.
     */
    all,

    /**
     * Register an event handler for the given type.
     * @param {string|symbol} type Type of event to listen for, or `'*'` for all events
     * @param {Function} handler Function to call in response to given event
     * @memberOf mitt
     */
    on<Key extends keyof Events>(type: Key, handler: GenericEventHandler) {
      const handlers: Array<GenericEventHandler> | undefined = all!.get(type);
      if (handlers) {
        handlers.push(handler);
      } else {
        all!.set(type, [handler] as EventHandlerList<Events[keyof Events]>);
      }
    },

    /**
     * Remove an event handler for the given type.
     * If `handler` is omitted, all handlers of the given type are removed.
     * @param {string|symbol} type Type of event to unregister `handler` from, or `'*'`
     * @param {Function} [handler] Handler function to remove
     * @memberOf mitt
     */
    off<Key extends keyof Events>(type: Key, handler?: GenericEventHandler) {
      const handlers: Array<GenericEventHandler> | undefined = all!.get(type);
      if (handlers) {
        if (handler) {
          handlers.splice(handlers.indexOf(handler) >>> 0, 1);
        } else {
          all!.set(type, []);
        }
      }
    },

    /**
     * Invoke all handlers for the given type.
     * If present, `'*'` handlers are invoked after type-matched handlers.
     *
     * Note: Manually firing '*' handlers is not supported.
     *
     * @param {string|symbol} type The event type to invoke
     * @param {Any} [evt] Any value (object is recommended and powerful), passed to each handler
     * @memberOf mitt
     */
    emit<Key extends keyof Events>(type: Key, evt?: Events[Key]) {
      let handlers = all!.get(type);
      if (handlers) {
        (handlers as EventHandlerList<Events[keyof Events]>)
          .slice()
          .map((handler) => {
            handler(evt!);
          });
      }

      handlers = all!.get('*');
      if (handlers) {
        (handlers as WildCardEventHandlerList<Events>)
          .slice()
          .map((handler) => {
            handler(type, evt!);
          });
      }
    },
  };
}

Ⅳ - difference between defaultChecked and checked

Note the difference between defaultChecked and checked. Similar examples are defaultValue and value

3. fetch send request

Concept: design idea of focusing on separation

  1. Fetch is the native AJAX interface provided by the browser.

Because the original XMLHttpRequest does not conform to the principle of separation of concerns, and the event-based model has less advantages than modern Promise in dealing with asynchrony. Therefore, Fetch appears to solve this problem.

  1. characteristic:

    • fetch: a native function that no longer uses the XmlHttpRequest object to submit ajax requests

    • Older browsers may not support

    • A request cannot be canceled using Fetch. This is because the Fetch API is based on Promise, which Promise cannot do. Since Fetch is a typical asynchronous scenario, most of the problems encountered are not Fetch, but Promise.

  2. If you use fetch directly, the result returned is not a direct result. It is just an HTTP response, not real data. There are two ways to obtain data:

    ① Use async+await to get

    ② Use the chain call of promise, return it in the first then, and use it in the next then

  3. Code example

//Code example
----------------------------- Not optimized:use then call chaining  ---------------------------------------------------------
fetch(`/api1/search/users2?q=${keyWord}`).then(
			response => {
				console.log('Successfully contacted the server');
				return response.json()
			},
			error => {
				console.log('Failed to contact the server',error);
				return new Promise(()=>{})
			}
		).then(
			response => {console.log('Data acquisition succeeded',response);},
			error => {console.log('Failed to get data',error);}
) 
----------------------------- After optimization:use async+await ---------------------------------------------------------
try {
		const response= await fetch(`/api1/search/users2?q=${keyWord}`)
		const data = await response.json()
		console.log(data);
		} catch (error) {
		onsole.log('Request error',error);
		}
}

Ⅳ - React routing

1. Relevant understanding

I - understanding of SPA

  1. single page web application (SPA).

  2. The whole application has only one complete page.

  3. Clicking the link in the page will not refresh the page, but only make a partial update of the page.

  4. All data needs to be obtained through ajax requests and presented asynchronously at the front end.

Ⅱ - understanding of routing

① What is routing?

  1. A route is a mapping relationship (key:value)

  2. key is the path, and value may be function or component

② Routing classification

1. Back end routing
  1. Understanding: value is a function used to process requests submitted by clients.

  2. Registered route: router get(path, function(req, res))

  3. Working process: when a node receives a request, it finds a matching route according to the request path, calls the functions in the route to process the request and return the response data

2. Front end routing
  1. Browser side routing. value is the component, which is used to display the page content.

  2. Register route: < route path = "/ test" component = {test} >

  3. Working process: when the path of the browser changes to / Test, the current routing component will change to Test component

ⅲ - understanding of react router DOM

① Related concepts

  1. react is a plug-in library.

  2. Designed to implement a SPA application.

  3. react based projects will basically use this library.

② Related APIs

1. Built in components
  1. <BrowserRouter>

  2. <HashRouter>

  3. <Route>

  4. <Redirect>

  5. <Link>

  6. <NavLink>

  7. <Switch>

2. Other
  1. history object

  2. match object

  3. withRouter function

2. Basic use of routing

1. Specify the navigation area and display area in the interface

2. The a label in the navigation area is changed to the Link label

 <Link to="/xxxxx">Demo</Link>

3. Write the Route label in the display area for path matching

<Route path='/xxxx' component={Demo}/>

4. The outermost side of < app > is wrapped with a < browserrouter > or < hashrouter >

ReactDOM.render(
	<BrowserRouter>
		<App/>
	</BrowserRouter>,
	document.getElementById('root')
)

3. Routing components and general components

1. Different writing methods:

General components: < demo / >

Routing component: < route path = "/ demo" component = {demo} / >

2. Different storage locations:

General components: components

Routing component: pages

  1. Different props received:

General components: when writing component labels, you can receive what is passed

Routing component: received three fixed attributes

//Display of routing attribute print results
history:
	go: ƒ go(n)
	goBack: ƒ goBack()
	goForward: ƒ goForward()
	push: ƒ push(path, state)
	replace: ƒ replace(path, state)
location:
    pathname: "/about"
	search: ""
	state: undefined
	match:
params: { }
	path: "/about"
	url: "/about"

4. NavLink usage and packaging

  1. NavLink can highlight routing links and specify the style name through activeClassName

  2. encapsulation

//Package example
export default class MyNavLink extends Component {
	render() {
		return (
			<NavLink activeClassName="atguigu" className="list-group-item" {...this.props}/>
		)
	}
}
  1. Use and call
//In native html, jump to different pages by < a >
{/* <a className="list-group-item" href="./about.html">About</a>
<a className="list-group-item active" href="./home.html">Home</a> */}

{/* Switch components by routing links in React -- write routing links */}
	<MyNavLink to="/about">About</MyNavLink>
	<MyNavLink to="/home">Home</MyNavLink>

5. Use of switches

1. Generally, path and component are one-to-one correspondence.

2.Switch can improve the efficiency of route matching (single matching) -- that is, after matching one, there will be no downward matching

<Switch>
	<Route path="/about" component={About}/>
	<Route path="/home" component={Home}/>
	<Route path="/home" component={Test}/>
</Switch>

6. Solve the problem that the page style of multi-level path refresh is lost

1.public/index. Do not write when introducing styles into HTML/ Write / (common)

2.public/index. Do not write when introducing styles into HTML/ Write% PUBLIC_URL% (commonly used, but only effective in react)

3. Use HashRouter (not commonly used)

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8" />
		<title>react Scaffolding</title>
       <!-- Method 2 -->
		<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
         <!-- Method 1 -->
		<link rel="stylesheet" href="/css/bootstrap.css">
	</head>
	<body>
		<div id="root"></div>
	</body>
</html>

7. Strict matching and fuzzy matching of routing

  1. Fuzzy matching is used by default (simply remember: the [entered path] must contain the [paths to be matched] in the same order)

  2. Enable strict matching: < route exact = {true} path = "/ about" component = {about} / >

You can omit exact={true} as exact

  1. Strict matching should not be started casually. It needs to be started again. Sometimes, it will make it impossible to continue matching secondary routes
//Write routing links
	<MyNavLink to="/about">About</MyNavLink>
	<MyNavLink to="/home/a/b">Home</MyNavLink>

{/* Register routing */}
	<Switch>
		<Route exact path="/about" component={About}/>
		<Route exact path="/home" component={Home}/>
	</Switch>

8. Use of Redirect

  1. It is usually written at the bottom of all route registrations. When all routes cannot be matched, jump to the route specified by Redirect

  2. Specific code:

	<Switch>
		<Route path="/about" component={About}/>
		<Route path="/home" component={Home}/>
		<Redirect to="/about"/>
	</Switch>

9. Nested routing

  1. When registering a child route, write the path value of the parent route

  2. Route matching is performed in the order of registering routes

-------------------Register first level routing-----------------------------
	{/* Switch components by routing links in React -- write routing links */}
	<MyNavLink to="/about">About</MyNavLink>
	<MyNavLink to="/home">Home</MyNavLink>
   {/* Register routing */}
	<Switch>
		<Route path="/about" component={About}/>
		<Route path="/home" component={Home}/>
		<Redirect to="/about"/>
	</Switch>
----------------------Register secondary routing :Home assembly-----------------------------------
   <div>
		<ul className="nav nav-tabs">
			<li>
				<MyNavLink to="/home/news">News</MyNavLink>
			</li>
			<li>
				<MyNavLink to="/home/message">Message</MyNavLink>
			</li>
		</ul>
		{/* Register routing */}
		<Switch>
			<Route path="/home/news" component={News}/>
			<Route path="/home/message" component={Message}/>
			<Redirect to="/home/news"/>
		</Switch>
	</div>

10. Pass parameters to routing components

I - params parameters

  1. Routing link (with parameters): < link to = '/ demo / test / Tom / 18'} > details < / link >

  2. Register route (claim receipt): < route path = "/ demo / test /: name /: age" component = {test} / >

  3. Receiving parameter: this props. match. params

	-------------------------------push parameter:Parent component----------------------------------------------
	<div>
       {/* Pass params parameter to routing component */}
       <Link to={`/home/message/detail/${msgObj.id}/${msgObj.title}`}>{msgObj.title}</Link>
       <hr />
       {/* Declare receive params parameter */}
       <Route path="/home/message/detail/:id/:title" component={Detail} />
  </div>
	--------------------------------Accept parameters:Subcomponents-----------------------------------------------------------
    const {id,title} = this.props.match.params

II - search parameter

  1. Routing link (with parameters): < link to = '/ demo / test? Name = Tom & age = 18 '} > details < / link >
  2. Register route (you can register normally without declaration): < route path = "/ demo / test" component = {test} / >
  3. Receiving parameter: this props. location. search
  4. Note: the obtained search is a urlencoded encoded string, which needs to be parsed with the help of querystring
	-------------------------------push parameter:Parent component----------------------------------------------
	<div>
      	{/* Pass the search parameter to the routing component */}
		<Link to={`/home/message/detail/?id=${msgObj.id}&title=${msgObj.title}`}>{msgObj.title}</Link>
       <hr />
     	{/* search The parameter does not need to declare receipt, and the route can be registered normally */}
		<Route path="/home/message/detail" component={Detail}/>
  </div>
	--------------------------------Accept parameters:Subcomponents-----------------------------------------------------------
    import qs from 'querystring'
	// Receive search parameter
	const {search} = this.props.location
	const {id,title} = qs.parse(search.slice(1))

Ⅲ - state parameter

  1. Routing link (with parameters): [< link to = {{pathname: '/ demo / test', state: {Name: 'Tom', age: 18}} > details < / link >]
  2. Register route (you can register normally without declaration): [< route path = "/ demo / test" component = {test} / >]
  3. Receiving parameter: this props. location. state
  • Note: the parameters can only be retained by refreshing with BrowserRouter. After refreshing with HashRouter, the state will have no history to save the parameters
  • Const {ID, title} = this props. location. State | {}, followed by | {} to prevent an error when the state is undefined after using HashRouter
	-------------------------------push parameter:Parent component----------------------------------------------
	<div>
      	{/* Pass the state parameter to the routing component */}
		<Link to={{pathname:'/home/message/detail',state:{id:msgObj.id,title:msgObj.title}}}>{msgObj.title}</Link>

       <hr />
     	{/* state The parameter does not need to declare receipt, and the route can be registered normally */}
		<Route path="/home/message/detail" component={Detail}/>
  </div>
	--------------------------------Accept parameters:Subcomponents-----------------------------------------------------------
    // Receive the state parameter and add ` | {} 'after it to prevent an error when the state is undefined after using' HashRouter '
	const {id,title} = this.props.location.state || {}

11. Programmed route navigation

With this prosp. The API on the history object controls the operation route jump, forward and backward

  1. -this.prosp.history.push()

Push history onto stack

  1. -this.props.history.replace()

Replace the stack position, that is, no history will be generated

  1. -this.props.history.goBack()

Back one space

  1. -this.props.history.goForward()

One space forward

  1. -this.props.history.go()

Forward or backward n spaces (positive or negative according to the number passed in)

import React, { Component } from 'react'
import { Link, Route } from 'react-router-dom'
import Detail from './Detail'

export default class Message extends Component {
 state = {
   messageArr: [
     { id: '01', title: 'Message 1' },
     { id: '02', title: 'Message 2' },
     { id: '03', title: 'Message 3' },
   ]
 }

 replaceShow = (id, title) => {
   //replace jump + params parameter carried
   //this.props.history.replace(`/home/message/detail/${id}/${title}`)

   //replace jump + carry search parameter
   // this.props.history.replace(`/home/message/detail?id=${id}&title=${title}`)

   //replace jump + carry state parameter
   this.props.history.replace(`/home/message/detail`, { id, title })
 }

 pushShow = (id, title) => {
   //push jump + params parameter carried
   // this.props.history.push(`/home/message/detail/${id}/${title}`)

   //push jump + carry search parameter
   // this.props.history.push(`/home/message/detail?id=${id}&title=${title}`)

   //push jump + carry state parameter
   this.props.history.push(`/home/message/detail`, { id, title })

 }

 back = () => {
   this.props.history.goBack()
 }

 forward = () => {
   this.props.history.goForward()
 }

 go = () => {
   this.props.history.go(-2)
 }

 render() {
   const { messageArr } = this.state
   return (
     <div>
       <ul>
         {
           messageArr.map((msgObj) => {
             return (
               <li key={msgObj.id}>

                 {/* Pass params parameter to routing component */}
                 {/* <Link to={`/home/message/detail/${msgObj.id}/${msgObj.title}`}>{msgObj.title}</Link> */}

                 {/* Pass the search parameter to the routing component */}
                 {/* <Link to={`/home/message/detail/?id=${msgObj.id}&title=${msgObj.title}`}>{msgObj.title}</Link> */}

                 {/* Pass the state parameter to the routing component */}
                 <Link to={{ pathname: '/home/message/detail', state: { id: msgObj.id, title: msgObj.title } }}>{msgObj.title}</Link>
			&nbsp;<button onClick={() => this.pushShow(msgObj.id, msgObj.title)}>push see</button>
			&nbsp;<button onClick={() => this.replaceShow(msgObj.id, msgObj.title)}>replace see</button>
               </li>
             )
           })
         }
       </ul>
       <hr />
       {/* Declare receive params parameter */}
       {/* <Route path="/home/message/detail/:id/:title" component={Detail}/> */}

       {/* search The parameter does not need to declare receipt, and the route can be registered normally */}
       {/* <Route path="/home/message/detail" component={Detail}/> */}

       {/* state The parameter does not need to declare receipt, and the route can be registered normally */}
       <Route path="/home/message/detail" component={Detail} />

       <button onClick={this.back}>Back off</button>&nbsp;
       <button onClick={this.forward}>forward</button>&nbsp;
       <button onClick={this.go}>go</button>
     </div>
   )
 }
}

12. Use of withRouter

  1. withRouter can process general components so that the general components have the unique API of routing components
  2. The return value of withRouter is a new component
import React, { Component } from 'react'
import { withRouter } from 'react-router-dom'
class Header extends Component {
 back = () => { this.props.history.goBack()}
 forward = () => {this.props.history.goForward()}
 go = () => { this.props.history.go(-2)}
 render() {
   console.log('Header Received by component props yes', this.props);
   return (
     <div className="page-header">
       <h2>React Router Demo</h2>
       <button onClick={this.back}>Back off</button>&nbsp;
       <button onClick={this.forward}>forward</button>&nbsp;
       <button onClick={this.go}>go</button>
     </div>
   )
 }
}
export default withRouter(Header)

13. Difference between BrowserRouter and HashRouter

Note: HashRouter can be used to solve some problems related to path errors. That is, when the file is introduced in question 6, the path can not be modified

I - the underlying principle is different:

  1. BrowserRouter uses the history API of H5 and is not compatible with IE9 and below.

But this is usually used

  1. HashRouter uses the hash value of the URL.

II - path has different forms

  1. There is no #, such as localhost:3000/demo/test, in the path of BrowserRouter

  2. The path of HashRouter contains #, for example: localhost:3000/#/demo/test

Ⅲ - impact on route state parameters after refresh

  1. BrowserRouter has no effect because the state is saved in the history object.

  2. After HashRouter is refreshed, the route state parameter will be lost!!!

Ⅴ-Ant Design

1. Related documents

Ant Design (domestic ant gold)

  1. Official website: https://ant.design/index-cn
  2. Github: https://github.com/ant-design/ant-design/

Material UI (abroad)

  1. Official website: http://www.material-ui.com/#/

  2. github: https://github.com/callemall/material-ui

2. Introduce and customize themes on demand

I - Installation dependency

yarn add react-app-rewired customize-cra babel-plugin-import less less-loader

II - modify package json

	"scripts": {
	"start": "react-app-rewired start",
	"build": "react-app-rewired build",
	"test": "react-app-rewired test",
	"eject": "react-scripts eject"
	},

III - create config overrides under the root directory js

Note: if you configure according to the custom theme of the official document, an error may be reported. You need to add an additional layer of lessOptions

//Configure specific modification rules
const { override, fixBabelImports,addLessLoader} = require('customize-cra');
module.exports = override(
	fixBabelImports('import', {
		libraryName: 'antd',
		libraryDirectory: 'es',
		style: true,
	}),
	addLessLoader({
		lessOptions:{
			javascriptEnabled: true,
			modifyVars: { '@primary-color': 'green' },
		}
	}),
-------------------Official method,Will report an error-------------------------    
+ addLessLoader({
+   javascriptEnabled: true,
+   modifyVars: { '@primary-color': '#1DA57A' },
+ }),
---------------------------------------------------------   
);

IV - success

Note: there is no need to introduce styles in the component, that is, import 'antd / dist / antd CSS' should be deleted

Ⅵ-Redux

1. redux understanding

I - learning documents

  1. English documents: https://redux.js.org/

  2. Chinese documents: http://www.redux.org.cn/

  3. Github: https://github.com/reactjs/redux

II - what is redux

  1. redux is a JS library dedicated to state management (not a react plug-in library).

  2. It can be used in react, angular, vue and other projects, but it is basically used in conjunction with react.

  3. Function: centrally manage the shared state of multiple components in react application.

III - under what circumstances do you need to use redux

  1. The status of a component needs to be available (shared) by other components at any time.

  2. One component needs to change the state (Communication) of another component.

  3. General principle: don't use it if you can. If you don't have to work hard, consider using it.

Ⅳ - redux workflow

[the external chain picture transfer fails. The source station may have an anti-theft chain mechanism. It is recommended to save the picture and upload it directly (img-JXjEifp8-1629693663557)(A_React system learning note / React system learning _reduxworkflow schematic. png)]

2. Three core concepts of redux

Ⅰ-action

  1. Action object

  2. Contains 2 attributes

    type: identifies the attribute. The value is a string. It is unique and necessary

    Data: data attribute, any value type, optional attribute

  3. Example: {type: 'ADD_STUDENT', data:{name: 'tom', age:18}}

Ⅱ-reducer

  1. Used for initialization status and machining status.
  2. During processing, the pure function of the new state is generated according to the old state and action (the following is the concept of pure function)``
  • ``Pure function: ` a special kind of function: as long as it is the same input (argument), it must get the same output (return)
  • Some of the following constraints must be observed
    1. Parameter data must not be overwritten
    2. There will be no side effects, such as network requests, input and output devices
    3. Cannot call date Now () or math Impure methods such as random()
  1. The reducer function of redux must be a pure function

Ⅲ-store

  1. An object that links state, action, and reducer

  2. How do I get this object?

    • import {createStore} from 'redux'
    • import reducer from './reducers'
    • const store = createStore(reducer)
  3. What is the function of this object?

    • getState(): get state

    • dispatch(action): distribute the action, trigger the reducer call, and generate a new state

    • subscribe(listener): register to listen. When a new state is generated, it will be called automatically

3. Core API of redux

I - createstore() and applymeddleware()

createstore() function: create a store object containing the specified reducer

applyMiddleware() function: redux based Middleware (plug-in library) in application

//Code example
---------------------------store.js Partial code---------------------------------
//createStore is introduced to create the most core store object in redux
import {createStore,applyMiddleware} from 'redux'
//Expose store
export default createStore(reducer,composeWithDevTools(applyMiddleware(thunk)))

II - store object

  1. Function: the core management object of redux Library

  2. It internally maintains:

    • state

    • reducer

  3. Core approach:

    • getState()

    • dispatch(action)

    • subscribe(listener)

  4. Specific code:

    • store.getState()

    • store.dispatch({type:'INCREMENT', number})

    • store.subscribe(render)

//Code example
---------------------------store.js---------------------------------
/**
* This file is written to expose a store object, and the whole application has only one store object
*/
//createStore is introduced to create the most core store object in redux
import {createStore,applyMiddleware} from 'redux'
//After importing the summarized reducer
import reducer from './reducers'
//Redux thunk is introduced to support asynchronous action s
import thunk from 'redux-thunk'
//Introducing Redux devtools extension
import {composeWithDevTools} from 'redux-devtools-extension'
//Expose store
export default createStore(reducer,composeWithDevTools(applyMiddleware(thunk)))
----------------------------index.js introduce store object--------------------------------
import React from 'react'
import ReactDOM from "react-dom"
import App from './App'
import store from './redux/store'
import {Provider} from 'react-redux'

ReactDOM.render(
	/* Here, you need to wrap the App with a Provider so that all descendant container components of the App can receive the store */
	<Provider store={store}>
		<App/>
	</Provider>,
	document.getElementById('root')
)

Ⅲ-combineReducers()

Function: merge multiple reducer functions

//Code example
------------------ redux/reducers/index.js ------------------------------------
/**
 * This file is used to summarize all reducers into a total reducer
 */
//combineReducers is introduced to summarize multiple reducers
import {combineReducers} from 'redux'
//Introduce reducer serving Count component
import count from './count'
import persons from './person'

//Summarize all reducers to become a total reducer
export default combineReducers({
  count,persons
})

4. redux asynchronous programming

I - Understanding

  1. By default, redux cannot perform asynchronous processing,

  2. Sometimes applications need to execute asynchronous tasks (ajax, timer) in redux

II - using asynchronous Middleware

  1. Download dependent NPM install -- save Redux thunk

  2. use

//Code example
---------------------------store.js---------------------------------
/**
 * This file is written to expose a store object, and the whole application has only one store object
 */
//createStore is introduced to create the most core store object in redux
import {createStore,applyMiddleware} from 'redux'
//After importing the summarized reducer
import reducer from './reducers'
//Redux thunk is introduced to support asynchronous action s
import thunk from 'redux-thunk'
//Introducing Redux devtools extension
import {composeWithDevTools} from 'redux-devtools-extension'
//Expose store
export default createStore(reducer,composeWithDevTools(applyMiddleware(thunk)))

5,react-redux

I - Understanding

  1. A react plug-in library

  2. Designed to simplify the use of redux in react applications

II - react Redux divides all components into two categories

① UI components

  1. It is only responsible for UI rendering without any business logic

  2. Receive data through props (general data and functions)

  3. Do not use any Redux API s

  4. It is generally saved in the components folder, or it can be written directly in the container component and processed directly into a container component

② Container assembly

  1. Responsible for managing data and business logic, not UI presentation

  2. Use Redux's API

  3. It is generally saved in the c ontainers folder

III - related API

① Provider

Function: let all components get state data

import React from 'react'
import ReactDOM from "react-dom"
import App from './App'
import store from './redux/store'
import {Provider} from 'react-redux'

ReactDOM.render(
	/* Here, you need to wrap the App with a Provider so that all descendant container components of the App can receive the store */
	<Provider store={store}>
		<App/>
	</Provider>,
	document.getElementById('root')
)

② connect()()

  1. Function: used to wrap UI components and generate container components

  2. Use connect(mapDispatchToProps,mapDispatchToProps)(UI component)

Note:

  1. This method passes in state and dispatch by default
  2. You can omit dispatch and directly pass in the action method, which will automatically call dispatch for you
Ⅰ-mapStateToProps

Function: converts external data (i.e. state object) into tag properties of UI components

1.mapStateToProps function returns an object;

2. The key in the returned object is the key passed to the UI component props, and the value is the value passed to the UI component props

3.mapStateToProps is used to transfer status

function mapStateToProps(state){
	return {count:state}
}
Ⅱ-mapDispatchToProps

Function: convert the function of distributing action into the tag attribute of UI component

  1. The mapDispatchToProps function returns an object;
  2. The key in the returned object is the key passed to the UI component props, and the value is the value passed to the UI component props
  3. mapDispatchToProps is the method used to pass operation status
  4. You can omit the dispatch and pass in the action directly. The API will call the dispatch automatically
III - code example
------------------------------Do not simplify code-----------------------------------------------
/* 
	1.mapStateToProps Function returns an object;
	2.The key in the returned object is the key passed to the UI component props, and the value is the value passed to the UI component props
	3.mapStateToProps Used to transfer status
*/
function mapStateToProps(state){
	return {count:state}
}

/* 
	1.mapDispatchToProps Function returns an object;
	2.The key in the returned object is the key passed to the UI component props, and the value is the value passed to the UI component props
	3.mapDispatchToProps Method for transferring operation status
*/
function mapDispatchToProps(dispatch){
	return {
		jia:number => dispatch(createIncrementAction(number)),
		jian:number => dispatch(createDecrementAction(number)),
		jiaAsync:(number,time) => dispatch(createIncrementAsyncAction(number,time)),
	}
}

//Use connect()() to create and expose a container component of Count
export default connect(mapStateToProps,mapDispatchToProps)(CountUI)

----------------Here is the simplified code-----------------------------
//Use connect()() to create and expose a container component of Count
//Use connect (incoming state, operation state method) (UI component)
export default connect(
 state => ({
   count: state.count,
   personCount: state.persons.length
 }),
 {increment, decrement, incrementAsync}
)(Count)

6. Using redux debugging tool

I - install the chrome browser plug-in

Redux DecTools

Ⅱ - download tool dependency package

npm install --save-dev redux-devtools-extension

III - modify store js

import {composeWithDevTools} from 'redux-devtools-extension'

/**
* This file is written to expose a store object, and the whole application has only one store object
*/
//createStore is introduced to create the most core store object in redux
import {createStore,applyMiddleware} from 'redux'
//After importing the summarized reducer
import reducer from './reducers'
//Redux thunk is introduced to support asynchronous action s
import thunk from 'redux-thunk'
//Introducing Redux devtools extension
import {composeWithDevTools} from 'redux-devtools-extension'
//Expose store
export default createStore(reducer,composeWithDevTools(applyMiddleware(thunk)))

VII - Redux summation case

Only the final code will be shown

Note: in the reducer, if the preState is an array, it cannot be modified by using push, unshift and other methods. Such modification will not modify its reference, so diff will not judge that it has changed, resulting in that the page cannot be automatically re rendered

	//preState.unshift(data) / / you can't write this here. This will cause the prestate to be rewritten, and the personReducer is not a pure function.
	return [data,...preState]

1. Summation case_ redux Lite

(1). Remove the state of the Count component itself

(2). Create under SRC:

​ -redux

​ -store.js

​ -count_reducer.js

(3).store.js:

​ 1). The createStore function in redux is introduced to create a store

​ 2). When createstore is called, a reducer serving it should be passed in

​ 3). Remember to expose the store object

(4).count_reducer.js:

​ 1). The essence of reducer is a function that receives: preState,action, and returns the processed state

​ 2).reducer has two functions: initialization status and machining status

​ 3). When the reducer is called for the first time, it is automatically triggered by the store,

The passed preState is undefined,

The action passed is: {type: '@ @ reduce / init_a.2. B.4}

(5). In index JS to monitor the change of state in the store, and re render once the change occurs

Note: redux is only responsible for managing the status. As for the change of status driving the display of the page, we have to write it ourselves

2. Summation case_ redux full version

New file:

1.count_action.js is specifically used to create action objects

2.constant.js places easily misspelled type values

3. Summation case_ redux asynchronous action version

(1). Clear: the delayed action does not want to be handed over to the component itself, but to the action

(2). When asynchronous action is needed: you want to operate on the status, but the specific data is returned by the asynchronous task.

(3). Specific code:

​ 1). Yarn add Redux thunk and configure it in the store

​ 2). The function that creates an action no longer returns a general object, but a function that writes asynchronous tasks.

​ 3). After the asynchronous task has a result, a synchronous action is distributed to actually operate the data.

(4). Note: asynchronous actions do not have to be written. You can wait for the results of asynchronous tasks before distributing synchronous actions.

4. Summation case_ Basic use of react Redux

(1). Define two concepts:

​ 1).UI component: you can't use any redux api, only responsible for page rendering, interaction, etc.

​ 2). Container component: responsible for communicating with redux and delivering the results to the UI component.

(2). How to create a container component -- rely on the connect function of react Redux

connect(mapStateToProps,mapDispatchToProps)(UI component)

- mapStateToProps: mapping state. The return value is an object

- mapDispatchToProps: method for mapping operation status. The return value is an object

(3). Note 1: the store in the container component is passed in by props, not directly introduced in the container component

(4). Note 2: mapDispatchToProps can also be an object

5. Summation case_ React Redux optimization

(1). Container components and UI components integrate into one file

(2). You don't need to pass the store to the container component, just give the package one.

(3). After using react Redux, there is no need to detect the change of state in redux. The container component can complete this work automatically.

(4).mapDispatchToProps can also be simply written as an object

(5). How many steps does a component have to go through to "deal with redux"?

​ (1). Defined UI components - not exposed

​ (2). Introduce connect to generate a container component and expose it as follows

connect(
      state => ({key:value}), //Mapping state
      {key:xxxxxAction} //Method of mapping operation state
     )(UI assembly)

​ (3). In the UI component, use this props. XXXXXXXX read and operation status

6. Summation case_ React Redux data sharing version

(1). Define a Pserson component and share data with the Count component through redux.

(2). Write: reducer and action for the Person component, and configure the constant constant constant.

(3). Important: the Person reducer and the Count reducer should be merged by using combineReducers. The total state after merging is one object!!!

(4). The store is handed over to the general reducer. Finally, when taking out the status in the component, remember to "take it in place".

7. Summation case_ Use of react Redux developer tools

(1).yarn add redux-devtools-extension

(2).store

​ import {composeWithDevTools} from 'redux-devtools-extension'

​ const store = createStore(allReducer,composeWithDevTools(applyMiddleware(thunk)))

8. Summation case_ React Redux final

(1). All variable names shall be standardized, and the short form of trigger object shall be used as much as possible.

(2). In the reducers folder, write index JS is specifically used to summarize and expose all reducers

9. Final code

I - src file directory

src

–containers

​ --Count

​ --index.jsx

​ --Person

​ --index.jsx

–redux

​ --actions

​ --count.js

​ --person.js

​ --reducers

​ --count.js

​ --index.js

​ --person.js

​ --constant.js

​ --store.js

–App.jsx

–index.js

Ⅱ-index.js

import React from 'react'
import ReactDOM from "react-dom"
import App from './App'
import store from './redux/store'
import {Provider} from 'react-redux'

ReactDOM.render(
	/* Here, you need to wrap the App with a Provider so that all descendant container components of the App can receive the store */
	<Provider store={store}>
		<App/>
	</Provider>,
	document.getElementById('root')
)

Ⅲ-App.jsx

import React, { Component } from 'react'
import Count from './containers/Count' //Container component of introduced Count
import Person from './containers/Person' //Container component of introduced Person

export default class App extends Component {
	render() {
		return (
			<div>
				<Count/>
				<hr/>
				<Person/>
			</div>
		)
	}
}

Ⅳ - redux file

  1. action folder
--------------------------------count.js------------------------------------------
/**
* The file does not generate objects specifically for the Count component
*/
import {INCREMENT,DECREMENT} from '../constant'

//Declaring a synchronous action means that the value of the action is a general Object of type Object
export const increment=data=>({type:INCREMENT,data})
export const decrement=data=>({type:DECREMENT,data})


//Declaring an asynchronous action means that the value of the action is a function. Synchronous actions are generally called in asynchronous actions
//When calling this action method externally, you need to introduce Redux thunk to support asynchronous actions
//This method automatically passes in dispatch
 export const incrementAsync=(data,time)=>{
   return (dispatch)=>{
     setTimeout(()=>{
       dispatch(increment(data))
     },time)
   }
 }
--------------------------------------person.js-------------------------------
import {ADD_PERSON} from '../constant'
//Create an action object to add a person
export const addPerson=personObj=>({
 type:ADD_PERSON,
 data:personObj
})
  1. reducers folder
--------------------------------count.js------------------------------------------
/**
* 1. This file is used to create a reducer that serves the Count component The essence of reducer is a function
* 2. reducer The function receives two parameters: pre state and action object
*/
import {
 INCREMENT,
 DECREMENT
} from '../constant'
const initState = 0 //Initialization status
export default function countReducer(preState = initState, action) {
 //Get: type:data from the action object
 const {
   type,
   data
 } = action
 //Determine how to process data according to type
 switch (type) {
   case INCREMENT:
     return preState + data
   case DECREMENT:
     return preState - data
   default:
     return preState
 }
}
--------------------------------------person.js-------------------------------
import {ADD_PERSON} from '../constant'
//Initializes the list of people
const initState = [{id:'001',name:'tom',age:18}]
export default function personReducer(preState=initState,action){
	// console.log('personReducer@#@#@#');
	const {type,data} = action
	switch (type) {
		case ADD_PERSON: //If you add a person
			//preState.unshift(data) / / you can't write this here. This will cause the prestate to be rewritten, and the personReducer is not a pure function.
			return [data,...preState]
		default:
			return preState
	}
}
--------------------------------------index.js-------------------------------
/**
* This file is used to summarize all reducers into a total reducer
*/
//combineReducers is introduced to summarize multiple reducers
import {combineReducers} from 'redux'
//Introduce reducer serving Count component
import count from './count'
import persons from './person'

//Summarize all reducers to become a total reducer
export default combineReducers({
 count,persons
})
  1. store.js
/**
* This file is written to expose a store object, and the whole application has only one store object
*/
//createStore is introduced to create the most core store object in redux
import {createStore,applyMiddleware} from 'redux'
//After importing the summarized reducer
import reducer from './reducers'
//Redux thunk is introduced to support asynchronous action s
import thunk from 'redux-thunk'
//Introducing Redux devtools extension
import {composeWithDevTools} from 'redux-devtools-extension'
//Expose store
export default createStore(reducer,composeWithDevTools(applyMiddleware(thunk)))

4.constant.js

/**
* This module is used to define the constant value of type in the action object. There is only one purpose:
*  Easy to manage colleagues to prevent programmers from writing wrong words
*/
export const INCREMENT = 'increment'
export const DECREMENT = 'decrement'
export const ADD_PERSON = 'add_person'

Ⅴ-containers

  1. Index. Of the Count folder jsx
import React, { Component } from 'react'

//Introduce action
import {
  increment,
  decrement,
  incrementAsync
} from "../../redux/actions/count"
//connect is introduced to link UI components with redux
import { connect } from 'react-redux'

//Define the UI component, which will be processed into a container component in connect()(), and then you can call its incoming redux status and actions
class Count extends Component {
  increment = () => {
    //Access content
    const { value } = this.selectNumber
    this.props.increment(value * 1)
  }
  //subtraction
  decrement = () => {
    const { value } = this.selectNumber
    this.props.decrement(value * 1)
  }
  //Odd plus
  incrementIfOdd = () => {
    const { value } = this.selectNumber
    if (this.props.count % 2 !== 0) {
      this.props.increment(value * 1)
    }
  }
  //Asynchronous addition
  incrementAsync = () => {
    const { value } = this.selectNumber
    this.props.incrementAsync(value * 1, 500)
  }

  render() {
    return (
      <div>
        <h2>I am Count assembly,The total number of people in the lower assembly is:{this.props.personCount}</h2>
        <h4>The current summation is:{this.props.count}</h4>
        <select ref={c => this.selectNumber = c}>
          <option value="1">1</option>
          <option value="2">2</option>
          <option value="3">3</option>
        </select>&nbsp;
        <button onClick={this.increment}>+</button>&nbsp;
        <button onClick={this.decrement}>-</button>&nbsp;
        <button onClick={this.incrementIfOdd}>The current sum is odd plus</button>&nbsp;
        <button onClick={this.incrementAsync}>Asynchronous addition</button>&nbsp;
      </div>
    )
  }

}


//Use connect()() to create and expose a container component of Count
//Use connect (incoming state, operation state method) (UI component)
export default connect(
  state => ({
    count: state.count,
    personCount: state.persons.length
  }),
  {increment, decrement, incrementAsync}
)(Count)

  1. jsx under Person folder
import React, { Component } from 'react'
import { connect } from 'react-redux'
import { addPerson } from '../../redux/actions/person'
import { nanoid } from 'nanoid'
//Create UI component
class Person extends Component {
  addPerson = () => {
    const name = this.nameNode.value
    const age = this.ageNode.value * 1
    const personObj = { id: nanoid(), name, age }
    this.props.addPerson(personObj)
    this.nameNode.value = ''
    this.ageNode.value = ''
  }

  render() {
    return (
      <div>
        <h2>I am Person assembly,The sum of the upper components is{this.props.count}</h2>
        <input ref={c => this.nameNode = c} type="text" placeholder="Enter name" />
        <input ref={c => this.ageNode = c} type="text" placeholder="Enter age" />
        <button onClick={this.addPerson}>add to</button>
        <ul>
          {
            this.props.persons.map((p) => {
              return <li key={p.id}>{p.name}--{p.age}</li>
            })
          }
        </ul>
      </div>
    )
  }
}
export default connect(
  state => ({
    persons: state.persons,
    count: state.count
  }), { addPerson }
)(Person)

Ⅷ - React expansion

1, setState

Two ways to write setState update state

(1). setState(stateChange, [callback]) ---- object type setState
1.stateChange is a state change object (this object can reflect the state change)
2.callback is an optional callback function. It is called only after the status is updated and the interface is updated (after render is called)

(2). setState(updater, [callback]) ---- functional setState

  • updater is a function that returns a stateChange object.
  • The updater can receive state and props.
  • Callback is an optional callback function. It is called only after the status is updated and the interface is updated (after render is called).

Summary:
1. Object type setState is the abbreviation of function type setState (syntax sugar)
2. Principle of use:
(1). If the new state does not depend on the original state = = = > use object mode
(2). If the new state depends on the original state = = = > use function mode
(3). If you need to obtain the latest state data after setState() is executed,
To read in the second callback function

import React, { Component } from 'react'
export default class Demo extends Component {
state = { count: 0 }
add = () => {
//Object style setState
/* //1.Get the original count value
const {count} = this.state
//2.Update status
this.setState({count:count+1},()=>{ console.log(this.state.count); })
//console.log('12 Output of line ', this state. count); // 0 */
//Functional setState
this.setState(state => ({ count: state.count + 1 }))
}
render() {
return (
<div>
  <h1>The current summation is:{this.state.count}</h1>
  <button onClick={this.add}>Point me+1</button>
</div>
)}}

2,lazyLoad

lazyLoad of routing component

  1. The components in lazy loading are used and adjusted at any time, and will not be loaded in advance
  2. When lazy loading is used, a fallback needs to be given. It is used to display when the request is too slow or the request cannot find a component. It is usually a component (or a virtual DOM directly)
  3. If fallback is specified as a component, the component must not be specified as a lazy loading component, just the component normally introduced
//	import Loading from './Loading '/ / used to specify ` fallback`
//1. Dynamically load the routing component through the lazy function of React and the import() function = = = > the routing component code will be packaged separately
	const Login = lazy(()=>import('@/pages/Login'))
	//2. Specify that a user-defined loading interface is displayed before loading the route packaging file through < suspend >
	<Suspense fallback={<h1>loading.....</h1>}>
    //< suspend fallback = {< loading / >} > specify as component                 
        <Switch>
            <Route path="/xxx" component={Xxxx}/>
            <Redirect to="/login"/>
        </Switch>
    </Suspense>

3,Hooks

See the next folder React Hooks notes for details

1. What is react hook / hooks?

(1). Hook is react 16.8 New features / syntax added in version 0
(2). You can use state and other React features in function components

2. Three commonly used hooks

(1). State Hook: React.useState()
(2). Effect Hook: React.useEffect()
(3). Ref Hook: React.useRef()

3. State Hook

(1). State Hook allows function components to have state and read and write state data
(2). Syntax: const [XXX, setXXX] = react useState(initValue)
(3). useState() Description:
Parameter: the specified value is cached internally during the first initialization
Return value: an array containing 2 elements. The first is the internal current status value, and the second is the function that updates the status value
(4). Setxxx() can be written in two ways:
setXxx(newValue): the parameter is a non function value, which directly specifies a new status value and internally overwrites the original status value
SetXXX (value = > newvalue): the parameter is a function that receives the original status value, returns a new status value, and internally overwrites the original status value

4. Effect Hook

(1). Effect Hook allows you to perform side-effect operations in function components (used to simulate life cycle hooks in class components)
(2). Side effects in react:
Send ajax request for data acquisition
Set subscription / start timer
Manually change the real DOM
(3). Syntax and Description:
useEffect(() => {
//Any operation with side effects can be performed here
Return() = > {/ / execute before uninstalling the component
//Do some finishing work here, such as clearing timer / unsubscribing, etc
}
}, [stateValue] / / if [] is specified, the callback function will only be executed after the first render()

(4). useEffect Hook can be regarded as a combination of the following three functions
componentDidMount()
componentDidUpdate()
componentWillUnmount()

5. Ref Hook

(1). Ref Hook can store / find tags or any other data in a function component
(2). Syntax: const refContainer = useRef()
(3). Function: save label object, function and react Createref()

	myRef = React.createRef()
	show = ()=>{
		alert(this.myRef.current.value)
	}

4, Fragment

  1. Function: you don't have to have a real DOM root tag

  2. When you have to use a container to wrap dom elements - jsx syntax requirements, we used to wrap a layer of div directly

  3. Using Fragment can replace div, but it will be discarded by react after compilation, so unnecessary hierarchical nesting will not be caused

  4. The effect is equivalent to writing an empty label < > < / >, but there is a difference between the two

    Difference: the key attribute can be added to the Fragment as the unique identifier, while the empty tag cannot be added at all

import React, { Component,Fragment } from 'react'

export default class Demo extends Component {
	render() {
		return (
			<Fragment key={1}> 
				<input type="text"/>
				<input type="text"/>
			</Fragment>
		)
	}
}

5,Context

A communication mode between components, which is often used for communication between [ancestor component] and [descendant component]

  1. Create Context container object:
	const XxxContext = React.createContext()  
  1. When rendering subgroups, wrap xxxcontext Provider to pass data to descendant components through the value attribute:
<xxxContext.Provider value={data}>
		Subcomponents
 </xxxContext.Provider>
  1. Descendant components read data: two methods
	//The first method: only applicable to class components 
​	  static contextType = xxxContext  // Claim receive context
​	  this.context // Read value data in context

​	//The second way: both function components and class components can be used
​	  <xxxContext.Consumer>
​	    {
​	      value => ( // Value is the value data in the context
​	        What to display
​	      )
​	    }
​	  </xxxContext.Consumer>

Note: context is generally not used in application development, and its encapsulated react plug-in is generally used

4) Complete example:

//-------------------Complete example------------------------------------------------
import React, { Component } from 'react'
import './index.css'
//Create Context object
const MyContext = React.createContext()
const {Provider,Consumer} = MyContext
export default class A extends Component {

	state = {username:'tom',age:18}

	render() {
		const {username,age} = this.state
		return (
			<div className="parent">
				<h3>I am A assembly</h3>
				<h4>My username is:{username}</h4>
				<Provider value={{username,age}}>
					<B/>
				</Provider>
			</div>
		)
	}
}

class B extends Component {
	render() {
		return (
			<div className="child">
				<h3>I am B assembly</h3>
				<C/>
			</div>
		)
	}
}

/* class C extends Component {
	//Claim receive context
	static contextType = MyContext
	render() {
		const {username,age} = this.context
		return (
			<div className="grand">
				<h3>I'm component C</h3>
				<h4>User name I received from component A: {username}, age {age} < / H4 >
			</div>
		)
	}
} */

function C(){
	return (
		<div className="grand">
			<h3>I am C assembly</h3>
			<h4>I from A The user name received by the component:
			<Consumer>
				{value => `${value.username},Age is ${value.age}`} //You can also return labels
			</Consumer>
			</h4>
		</div>
	)
}

6. Component optimization – PureComponent

Two problems of Ⅰ - Component

  1. As long as setState() is executed, even if the state data is not changed, the component will re render() = = > which is inefficient
  2. Re render() only the current component will automatically re render the child components, even if the child components do not use any data of the parent component = = > low efficiency

II - efficient practices:

Re render() only when the state or props data of the component changes

III - cause analysis

shouldComponentUpdate() in Component always returns true

Optimization solution

Method 1:
Override shouldComponentUpdate() method
Compare the old and new state or props data. If there is any change, it returns true. If there is no change, it returns false
Method 2:
Using PureComponent
PureComponent overrides shouldComponentUpdate(), and returns true only when the state or props data changes
be careful:
It only makes a shallow comparison between state and props data. If only the internal data of the data object changes, false is returned
Do not modify the state data directly, but generate new data
PureComponent is generally used to optimize in projects

Optimization code example:

import React, { PureComponent } from 'react'
import './index.css'
export default class Parent extends PureComponent {
 state = { carName: "Benz c36", stus: ['Xiao Zhang', 'petty thief', 'Xiao Wang'] }
 addStu = () => {
   /* const {stus} = this.state
   stus.unshift('Xiao Liu ')
   this.setState({stus}) */
   const { stus } = this.state
   this.setState({ stus: ['Xiao Liu', ...stus] })
 }

 changeCar = () => {
   //this.setState({carName: 'Maybach'})

   const obj = this.state
   obj.carName = 'Maybach '
   console.log(obj === this.state);
   this.setState(obj)
 }

 /* shouldComponentUpdate(nextProps,nextState){
   // console.log(this.props,this.state); //Current props and state
   // console.log(nextProps,nextState); //Next, the target props and target state to be changed
   return !this.state.carName === nextState.carName
 } */

 render() {
   console.log('Parent---render');
   const { carName } = this.state
   return (
     <div className="parent">
       <h3>I am Parent assembly</h3>
       {this.state.stus}&nbsp;
       <span>My car name is:{carName}</span><br />
       <button onClick={this.changeCar}>I'll change trains at 8:00</button>
       <button onClick={this.addStu}>Add a Xiao Liu</button>
       <Child carName="Alto" />
     </div>
   )
 }
}

class Child extends PureComponent {
 /* shouldComponentUpdate(nextProps,nextState){
   console.log(this.props,this.state); //Current props and state
   console.log(nextProps,nextState); //Next, the target props and target state to be changed
   return !this.props.carName === nextProps.carName
 } */
 render() {
   console.log('Child---render');
   return (
     <div className="child">
       <h3>I am Child assembly</h3>
       <span>The car I received was:{this.props.carName}</span>
     </div>
   )
 }
}

7. render props - similar vue slot

  1. How to dynamically transfer a structure (label) with content into a component?

In Vue:
Using slot technology, that is, passing in the structure through the component tag body
In React:
Use children props: pass in the structure through the component label body
Use render props: the structure is passed in through the component tag attribute, and data can be carried. Generally, the render function attribute is used

  1. children props
<A>
  <B>xxxx</B>
</A>
{this.props.children}
problem: If B Component needs A Data in components, ==> can't meet the requirements 
  1. render props
<A render={(data) => <C data={data}></C>}></A>
A assembly: {this.props.render(inside state data)}
C assembly: read A Component incoming data display {this.props.data}
  1. Example
import React, { Component } from 'react'
import './index.css'
import C from '../1_setState'

export default class Parent extends Component {
	render() {
		return (
			<div className="parent">
				<h3>I am Parent assembly</h3>
				<A render={(name)=><C name={name}/>}/>
			</div>
		)
	}
}

class A extends Component {
	state = {name:'tom'}
	render() {
		console.log(this.props);
		const {name} = this.state
		return (
			<div className="a">
				<h3>I am A assembly</h3>
				{this.props.render(name)}
			</div>
		)
	}
}

class B extends Component {
	render() {
		console.log('B--render');
		return (
			<div className="b">
				<h3>I am B assembly,{this.props.name}</h3>
			</div>
		)
	}
}

8. Error boundary

  1. understand:

Error boundary: it is used to capture the errors of descendant components and render standby pages

  1. characteristic:

It can only capture the errors generated by the life cycle of descendant components, not the errors generated by its own components and the errors generated by other components in synthetic events and timers

  1. getDerivedStateFromError with componentDidCatch
// The lifecycle function will be triggered once the background component reports an error
static getDerivedStateFromError(error) {
    console.log(error);
    // Triggered before render
    // Return to new state
    return {
        hasError: true,
    };
}

componentDidCatch(error, info) {
    // Error in Statistics page. Send request to the background
    console.log(error, info);
}
  1. Code example
import React, { Component } from 'react'
import Child from './Child'

export default class Parent extends Component {

  state = {
    hasError: '' //Used to identify whether the subcomponent generated an error
  }

  //When the child component of the Parent reports an error, it will trigger the call getDerivedStateFromError and carry the error information
  static getDerivedStateFromError(error) {
    console.log('@@@', error);
    return { hasError: error }
  }

  componentDidCatch() {
    console.log('Here, the statistics error is fed back to the server to notify the coder to perform the statistics bug Solution');
  }

  render() {
    return (
      <div>
        <h2>I am Parent assembly</h2>
        {this.state.hasError ? <h2>The current network is unstable. Please try again later</h2> : <Child />}
      </div>
    )
  }
}

9. Summary of component communication methods

  1. Relationship between components:
  • Parent child component
  • Sibling component (non nested component)
  • Grandparent component (cross level component)
  1. Several communication modes:

    - props: 
         1).children props
         (2).render props
    
    - Message subscription-release:
         ubs-sub,event wait
    
    - Centralized management:
         edux,dva wait
    
    - conText:
         Producer-Consumer model
    
  2. Better collocation

    - Parent child components: props
    - Brother component: message subscription-Publishing, centralized management
    - Grandson assembly(Cross level components): Message subscription-Publishing, centralized management conText(Use less for development and more for packaging plug-ins)
    

IX - example of communication between components

1. Value transfer method between brothers 1 -- > [child to parent, parent to child]

  1. The parent component defines a [state] or [method], where [method] can modify [state]
  • Pass the [method] to the child component to send the value, and modify the [state] of the parent component through the inherited [method]
  • Pass the [status] to the sub component to accept the value, so that the value can be passed between brothers
  1. Code example
----------Parent component------------------------
class Main extends React.Component<IProps> {
  constructor(props) {
    super(props);
    this.state = { searchParams: {} };
  }
  handleIPSearch = (params) => {
    this.setState({ searchParams: params });
  };
  render() {
    <Sub assembly 1:To modify component 2 handleIPSearch={handleIPSearch}  />
    <Sub assembly 2:Value to accept    searchParams={this.state.searchParams}/>
  }
}
--------------Sub assembly 1----------------------
const ManageTable = (props: IProps) => {
 const {  handleIPSearch } = props;
 return(
     //Here you can call the function to modify the state of the parent component
    <a onClick={() => {   handleIPSearch(data) }} >
    Modify the parent component value,Indirectly change the value received by component 2
  </a>)
}
--------------Sub assembly 2----------------------
const IPInfo: FC = (props) => {
    //The state of the parent component can be used here
  const { searchParams } = props;
    return( <span>searchParams</span> )    
}

2. Inter brother value transfer mode 2 -- > [MIT (publish subscriber mode)]

This method is implemented with [MIT]. In fact, it essentially registers a global variable for listening -- > MIT source address

You can implement it yourself. Here, because others write well, take this as an example

  1. Install or copy directly
npm install --save mitt
  1. Use example
-------------- First define a common global variable  --------------------------
//File utils / index ts
import mitt from './mitt';
//Declare it here and make it a global variable
const eventBus = mitt();
export { eventBus }
---------------- Components that send values(To modify someone else's component)  ---------------------
//Import common variables
import { eventBus } from '~/utils';
  <a
  onClick={() => {
	//Delayed sending means that I have a jump action before this and jump to the receiver component
    // When the value is modified, but the receiving component is not registered, it can be sent directly under normal conditions     
    //setTimeout(() => {
    // eventBus.emit('foo', data);
    //}, 100);
    eventBus.emit('foo', data);    
   }}
  />;
    
------------------ Receiver component(Accept sender's component)  -------------------------------------
    
const Search: FC<IProps> = (props) => {
  useEffect(() => {
    //Replace with mitt writing method. At this time, it has been received
    eventBus.on('foo', (searchParams) => {console.log('Value accepted',searchParams) }
    });
  }, []);
} 
  1. MIT source code
export type EventType = string | symbol;

// An event handler can take an optional event argument
// and should not return a value
export type Handler<T = unknown> = (event: T) => void;
export type WildcardHandler<T = Record<string, unknown>> = (
  type: keyof T,
  event: T[keyof T]
) => void;

// An array of all currently registered event handlers for a type
export type EventHandlerList<T = unknown> = Array<Handler<T>>;
export type WildCardEventHandlerList<T = Record<string, unknown>> = Array<
  WildcardHandler<T>
>;

// A map of event types and their corresponding event handlers.
export type EventHandlerMap<Events extends Record<EventType, unknown>> = Map<
  keyof Events | '*',
  EventHandlerList<Events[keyof Events]> | WildCardEventHandlerList<Events>
>;

export interface Emitter<Events extends Record<EventType, unknown>> {
  all: EventHandlerMap<Events>;

  on: (<Key extends keyof Events>(type: Key, handler: Handler<Events[Key]>) => void) & ((type: '*', handler: WildcardHandler<Events>) => void);

  off: (<Key extends keyof Events>(
    type: Key,
    handler?: Handler<Events[Key]>
  ) => void) & ((type: '*', handler: WildcardHandler<Events>) => void);

  emit: (<Key extends keyof Events>(type: Key, event: Events[Key]) => void) & (<Key extends keyof Events>(
    type: undefined extends Events[Key] ? Key : never
  ) => void);
}

/**
 * Mitt: Tiny (~200b) functional event emitter / pubsub.
 * @name mitt
 * @returns {Mitt}
 */
export default function mitt<Events extends Record<EventType, unknown>>(
  all?: EventHandlerMap<Events>
): Emitter<Events> {
  type GenericEventHandler =
    | Handler<Events[keyof Events]>
    | WildcardHandler<Events>;
  all = all || new Map();

  return {
    /**
     * A Map of event names to registered handler functions.
     */
    all,

    /**
     * Register an event handler for the given type.
     * @param {string|symbol} type Type of event to listen for, or `'*'` for all events
     * @param {Function} handler Function to call in response to given event
     * @memberOf mitt
     */
    on<Key extends keyof Events>(type: Key, handler: GenericEventHandler) {
      const handlers: Array<GenericEventHandler> | undefined = all!.get(type);
      if (handlers) {
        handlers.push(handler);
      } else {
        all!.set(type, [handler] as EventHandlerList<Events[keyof Events]>);
      }
    },

    /**
     * Remove an event handler for the given type.
     * If `handler` is omitted, all handlers of the given type are removed.
     * @param {string|symbol} type Type of event to unregister `handler` from, or `'*'`
     * @param {Function} [handler] Handler function to remove
     * @memberOf mitt
     */
    off<Key extends keyof Events>(type: Key, handler?: GenericEventHandler) {
      const handlers: Array<GenericEventHandler> | undefined = all!.get(type);
      if (handlers) {
        if (handler) {
          handlers.splice(handlers.indexOf(handler) >>> 0, 1);
        } else {
          all!.set(type, []);
        }
      }
    },

    /**
     * Invoke all handlers for the given type.
     * If present, `'*'` handlers are invoked after type-matched handlers.
     *
     * Note: Manually firing '*' handlers is not supported.
     *
     * @param {string|symbol} type The event type to invoke
     * @param {Any} [evt] Any value (object is recommended and powerful), passed to each handler
     * @memberOf mitt
     */
    emit<Key extends keyof Events>(type: Key, evt?: Events[Key]) {
      let handlers = all!.get(type);
      if (handlers) {
        (handlers as EventHandlerList<Events[keyof Events]>)
          .slice()
          .map((handler) => {
            handler(evt!);
          });
      }

      handlers = all!.get('*');
      if (handlers) {
        (handlers as WildCardEventHandlerList<Events>)
          .slice()
          .map((handler) => {
            handler(type, evt!);
          });
      }
    },
  };
}