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
- webpack related knowledge
- axios related knowledge
- js foundation and es6 related knowledge
1, About React
- Official website link: Chinese official website
- Introduction description
- JavaScript for dynamically building user interfaces (focusing only on views)
- Open source by Facebook
1. Characteristics of React
-
Declarative programming
-
Component programming
-
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
- Efficient (excellent Diffing algorithm)
2. Why React is efficient
- With virtual DOM, you DON't always directly manipulate the real DON of the page
- DOM Diffing algorithm to minimize page redrawing
- 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
- An Object of type Object (general Object) when it is intrinsic
- 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)
- 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
- When defining a virtual DOM, do not write quotation marks
- Use {} when mixing JS expressions into tags
- The class name of the style specifies to use className instead of class
- The inline style should be written in the form of style={{key:value}} (double {} represents an object and single {} represents an expression)
- Only one tag (the entire virtual DOM is wrapped in an outer layer and only one container)
- The label must be closed
- 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]
- Expression: an expression will produce a value, which can be placed wherever a value is required
These are expressions
-
a
-
a+b
-
demo(1)
-
arr.map()
-
function test(){}
-
Statement: cannot be placed in a statement that creates a virtual dom
-
if(){}
-
for(){}
-
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
- Understanding: a js program that provides specific functions externally is generally a js file
- Why break it into modules: as business logic increases, code becomes more and more complex
- 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
-
Understanding: a collection of code and resources used to achieve local functional effects (html/css/js/img, etc.)
-
Why use components: the functionality of an interface is complex
-
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
- Debug using React developer tools
React Developer Tools
- 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 < / >
- 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
- 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)
- 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
-
this in the render method in the component is the component instance object
-
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
- 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
- Each component object will have props (short for properties) attribute
- All properties of the component tag are saved in props
② Function
- Changing data is transferred from the outside to the inside of the component through tag attributes
- 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"/> <button onClick={this.showData}>Click the data on the left of my prompt</button> <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"/> <button onClick={this.showData}>Click the data on the left of my prompt</button> <input onBlur={this.showData2} ref={c => this.input2 = c } type="text" placeholder="Lost focus prompt data"/> </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"/> <button onClick={this.showData}>Click the data on the left of my prompt</button> <input onBlur={this.showData2} ref={this.myRef2} type="text" placeholder="Lost focus prompt data"/> </div> ) } }
4. Event handling and form data collection
I - event handling
- 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
- 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
- If the parameter accepted by A function is A function, then A can be called A higher-order function
- 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
- A component goes through some specific stages from creation to death
- The React component contains a series of hook functions (life cycle callback functions), which will be called at a specific time
- 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
-
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
-
-
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
-
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)
-
Initialization phase: by reactdom Render() trigger - first render
- constructor()
- getDerivedStateFromProps() get derived state from Props
- render()
- Componentdidmount() = = = > common
-
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()
-
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
- render: call to initialize rendering or update rendering
- componentDidMount(): enable listening and send ajax requests
- componentWillUnmount(): do some finishing work, such as cleaning up the timer
4. Hook to be discarded
- componentWillMount
- componentWillReceiveProps
- 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:
-
To put it simply: key is the identifier of the virtual DOM object and plays an extremely important role in updating the display
-
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:
-
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
-
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:
- 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
- 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
- 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?
- It is better to use the unique identifier of each data as key, such as id, mobile phone number, id number, student number, etc.
- 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
- 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
-
React provides a scaffolding library for creating react projects: create react app
-
The overall technical architecture of the project is: react+webpack+es6+eslint
-
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
-
Global installation: NPM I - G create react app
-
Switch to the directory where you want to create the project and use the command: create react arr Hello react
-
Enter project folder
-
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
-
Split component: split interface, extract components
-
Implement static components: use components to achieve static page effects
-
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
- 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)
- 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
- Install or copy directly
npm install --save mitt
- 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) } }); }, []); }
- 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
- 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.
-
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.
-
-
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
-
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
-
single page web application (SPA).
-
The whole application has only one complete page.
-
Clicking the link in the page will not refresh the page, but only make a partial update of the page.
-
All data needs to be obtained through ajax requests and presented asynchronously at the front end.
Ⅱ - understanding of routing
① What is routing?
-
A route is a mapping relationship (key:value)
-
key is the path, and value may be function or component
② Routing classification
1. Back end routing
-
Understanding: value is a function used to process requests submitted by clients.
-
Registered route: router get(path, function(req, res))
-
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
-
Browser side routing. value is the component, which is used to display the page content.
-
Register route: < route path = "/ test" component = {test} >
-
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
-
react is a plug-in library.
-
Designed to implement a SPA application.
-
react based projects will basically use this library.
② Related APIs
1. Built in components
-
<BrowserRouter>
-
<HashRouter>
-
<Route>
-
<Redirect>
-
<Link>
-
<NavLink>
-
<Switch>
2. Other
-
history object
-
match object
-
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
- 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
-
NavLink can highlight routing links and specify the style name through activeClassName
-
encapsulation
//Package example export default class MyNavLink extends Component { render() { return ( <NavLink activeClassName="atguigu" className="list-group-item" {...this.props}/> ) } }
- 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
-
Fuzzy matching is used by default (simply remember: the [entered path] must contain the [paths to be matched] in the same order)
-
Enable strict matching: < route exact = {true} path = "/ about" component = {about} / >
You can omit exact={true} as exact
- 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
-
It is usually written at the bottom of all route registrations. When all routes cannot be matched, jump to the route specified by Redirect
-
Specific code:
<Switch> <Route path="/about" component={About}/> <Route path="/home" component={Home}/> <Redirect to="/about"/> </Switch>
9. Nested routing
-
When registering a child route, write the path value of the parent route
-
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
-
Routing link (with parameters): < link to = '/ demo / test / Tom / 18'} > details < / link >
-
Register route (claim receipt): < route path = "/ demo / test /: name /: age" component = {test} / >
-
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
- Routing link (with parameters): < link to = '/ demo / test? Name = Tom & age = 18 '} > details < / link >
- Register route (you can register normally without declaration): < route path = "/ demo / test" component = {test} / >
- Receiving parameter: this props. location. search
- 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
- Routing link (with parameters): [< link to = {{pathname: '/ demo / test', state: {Name: 'Tom', age: 18}} > details < / link >]
- Register route (you can register normally without declaration): [< route path = "/ demo / test" component = {test} / >]
- 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
- -this.prosp.history.push()
Push history onto stack
- -this.props.history.replace()
Replace the stack position, that is, no history will be generated
- -this.props.history.goBack()
Back one space
- -this.props.history.goForward()
One space forward
- -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> <button onClick={() => this.pushShow(msgObj.id, msgObj.title)}>push see</button> <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> <button onClick={this.forward}>forward</button> <button onClick={this.go}>go</button> </div> ) } }
12. Use of withRouter
- withRouter can process general components so that the general components have the unique API of routing components
- 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> <button onClick={this.forward}>forward</button> <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:
- BrowserRouter uses the history API of H5 and is not compatible with IE9 and below.
But this is usually used
- HashRouter uses the hash value of the URL.
II - path has different forms
-
There is no #, such as localhost:3000/demo/test, in the path of BrowserRouter
-
The path of HashRouter contains #, for example: localhost:3000/#/demo/test
Ⅲ - impact on route state parameters after refresh
-
BrowserRouter has no effect because the state is saved in the history object.
-
After HashRouter is refreshed, the route state parameter will be lost!!!
Ⅴ-Ant Design
1. Related documents
Ant Design (domestic ant gold)
- Official website: https://ant.design/index-cn
- Github: https://github.com/ant-design/ant-design/
Material UI (abroad)
-
Official website: http://www.material-ui.com/#/
-
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
-
English documents: https://redux.js.org/
-
Chinese documents: http://www.redux.org.cn/
-
Github: https://github.com/reactjs/redux
II - what is redux
-
redux is a JS library dedicated to state management (not a react plug-in library).
-
It can be used in react, angular, vue and other projects, but it is basically used in conjunction with react.
-
Function: centrally manage the shared state of multiple components in react application.
III - under what circumstances do you need to use redux
-
The status of a component needs to be available (shared) by other components at any time.
-
One component needs to change the state (Communication) of another component.
-
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
-
Action object
-
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
-
Example: {type: 'ADD_STUDENT', data:{name: 'tom', age:18}}
Ⅱ-reducer
- Used for initialization status and machining status.
- 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
- Parameter data must not be overwritten
- There will be no side effects, such as network requests, input and output devices
- Cannot call date Now () or math Impure methods such as random()
- The reducer function of redux must be a pure function
Ⅲ-store
-
An object that links state, action, and reducer
-
How do I get this object?
- import {createStore} from 'redux'
- import reducer from './reducers'
- const store = createStore(reducer)
-
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
-
Function: the core management object of redux Library
-
It internally maintains:
-
state
-
reducer
-
-
Core approach:
-
getState()
-
dispatch(action)
-
subscribe(listener)
-
-
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
-
By default, redux cannot perform asynchronous processing,
-
Sometimes applications need to execute asynchronous tasks (ajax, timer) in redux
II - using asynchronous Middleware
-
Download dependent NPM install -- save Redux thunk
-
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
-
A react plug-in library
-
Designed to simplify the use of redux in react applications
II - react Redux divides all components into two categories
① UI components
-
It is only responsible for UI rendering without any business logic
-
Receive data through props (general data and functions)
-
Do not use any Redux API s
-
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
-
Responsible for managing data and business logic, not UI presentation
-
Use Redux's API
-
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()()
-
Function: used to wrap UI components and generate container components
-
Use connect(mapDispatchToProps,mapDispatchToProps)(UI component)
Note:
- This method passes in state and dispatch by default
- 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
- The mapDispatchToProps function returns an object;
- 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
- mapDispatchToProps is the method used to pass operation status
- 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
- 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 })
- 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 })
- 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
- 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> <button onClick={this.increment}>+</button> <button onClick={this.decrement}>-</button> <button onClick={this.incrementIfOdd}>The current sum is odd plus</button> <button onClick={this.incrementAsync}>Asynchronous addition</button> </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)
- 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
- The components in lazy loading are used and adjusted at any time, and will not be loaded in advance
- 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)
- 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
-
Function: you don't have to have a real DOM root tag
-
When you have to use a container to wrap dom elements - jsx syntax requirements, we used to wrap a layer of div directly
-
Using Fragment can replace div, but it will be discarded by react after compilation, so unnecessary hierarchical nesting will not be caused
-
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]
- Create Context container object:
const XxxContext = React.createContext()
- When rendering subgroups, wrap xxxcontext Provider to pass data to descendant components through the value attribute:
<xxxContext.Provider value={data}> Subcomponents </xxxContext.Provider>
- 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
- As long as setState() is executed, even if the state data is not changed, the component will re render() = = > which is inefficient
- 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} <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
- 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
- children props
<A> <B>xxxx</B> </A> {this.props.children} problem: If B Component needs A Data in components, ==> can't meet the requirements
- 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}
- 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
- understand:
Error boundary: it is used to capture the errors of descendant components and render standby pages
- 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
- 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); }
- 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
- Relationship between components:
- Parent child component
- Sibling component (non nested component)
- Grandparent component (cross level component)
-
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
-
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]
- 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
- 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
- Install or copy directly
npm install --save mitt
- 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) } }); }, []); }
- 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!); }); } }, }; }