react learning notes

js create virtual dom and jsx create virtual dom

  • js to create a virtual dom

     <!-- Prepare a "container" -->
     <div id="test"></div>
    
     <!-- introduce react Core library -->
     <script type="text/javascript" src="../js/react.development.js"></script>
     <!-- introduce react-dom,Used to support react operation DOM -->
     <script type="text/javascript" src="../js/react-dom.development.js"></script>
    
     <script type="text/javascript" > 
     	//1. Create virtual DOM
     	const VDOM = React.createElement('h1',{id:'title'},React.createElement('span',{},'Hello,React'))
     	//2. Render virtual DOM to page
     	ReactDOM.render(VDOM,document.getElementById('test'))
     </script>
    

js to create a virtual dom, if there is a nested structure, it is cumbersome!

  • Creating a virtual dom using jsx

     <!-- Prepare a "container" -->
     <div id="test"></div>
    
     <!-- introduce react Core library -->
     <script type="text/javascript" src="../js/react.development.js"></script>
     <!-- introduce react-dom,Used to support react operation DOM -->
     <script type="text/javascript" src="../js/react-dom.development.js"></script>
     <!-- introduce babel,Used to jsx Turn into js -->
     <script type="text/javascript" src="../js/babel.min.js"></script>
    
     <script type="text/babel" > /* Be sure to write babel here */
     	//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'))
     </script>
    

jsx will eventually be compiled into js code by babel

  • Comparison between virtual dom and real dom

     <script type="text/babel" > /* Be sure to write babel here */
     	//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'))
    
     	const TDOM = document.getElementById('demo')
     	console.log('fictitious DOM',VDOM);
     	console.log('real DOM',TDOM);
     	debugger;
     	// console.log(typeof VDOM);
     	// console.log(VDOM instanceof Object);
     	/* 
     			About virtual DOM:
     				1.An Object of type Object (general Object) in essence
     				2.The virtual DOM is "light" and the real DOM is "heavy", because the virtual DOM is used inside React and does not need so many attributes on the real dom.
     				3.The virtual DOM will eventually be transformed into a real DOM by React and presented on the page.
     	 */
     </script>
    

There are fewer attributes on the virtual dom

About jsx

  • In the tag code in jsx, if you want to write js code, you need to add {}, and only one expression can be written in {}

    • The statements in {} can assign values to variables, which are expressions, such as arr.map(), function test() {}
  • In the jsx tag code, if you write an array, it will be directly traversed

  • more

/* 
				jsx rule of grammar:
						1.When defining a virtual DOM, do not write quotation marks.
						2.Use {} when mixing JS expressions into tags.
						3.The class name of the style specifies to use className instead of class.
						4.The inline style should be written in the form of style={{key:value}}.
						5.There is only one root label
						6.The label must be closed
						7.Label initials
								(1).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.
								(2).If it starts with a capital letter, react will render the corresponding component. If the component is not defined, an error will be reported.

		 */

Functional and class components

  • Functional component

    • Functional components are called by window, and strict mode is enabled in babel, so this here is undefined!

    • <script type="text/babel">
      		//1. Create functional components
      		function MyComponent(){
      			console.log(this); //this is undefined here because strict mode is enabled after babel compilation
      			return <h2>I'm a component defined by a function(It is applicable to the definition of [simple component])</h2>
      		}
      		//2. Render component to page
      		ReactDOM.render(<MyComponent/>,document.getElementById('test'))
      		/* 
      			Executed reactdom What happens after render (< mycomponent / >)?
      					1.React Parsing the component tag, found 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 appears in the page.
      		*/
      	</script>
      
  • Class component

    • Is an inheritance from react Class of component
    • To override the render method of the parent class
    • Its state and props are in the instance
    • This in the method is determined by the caller, and this in render points to the instance
    • The render method will be called when initialized and updated.
    • Through this Setstate ({}) can update the components on the page, and the setState() method is on the parent class

Three properties in components

Class component

state

  • Initialize state

    • Initialize state in constructor
      • this.state = {isHot:false,wind: 'breeze'}
  • Get the value in state

    • this in render points to the instance
    • If the callback function in the onClick event is the method of the prototype object and passes this When state gets the status, an error will be reported because this point is not called by the component object, but by window, so this point is undefined
  • Operate on state

    • Cannot operate directly!
    • Use this Setstate() operation, and this Setstate () will merge the properties in the previous state, not replace
  • Solve this pointing problem

    • In the constructor, this changeWeather = this. changeWeather. Bind (this) will add the function after changing the point of this in the class on the current instance

    • Add arrow function method to instance

      • 	<script type="text/babel">
        		//1. Create component
        		class Weather extends React.Component{
        			//Initialization status
                    //Status properties on instances
        			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'))
        				
        	</script>
        

props

  • Pass props attribute, reactdom render(<Person {…p}/>,document.getElementById(‘test3’))

  • Get props, this props

  • Limit props

    • Restrict the props of the component and set the default props property, which can only be written in the prototype object of the instance

      • 	    //First Chinese writing
                //Limit the type and necessity of label attributes
              		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
              			speak:PropTypes.func,//Restrict speak to function
              		}
              		//Specifies the default label attribute value
              		Person.defaultProps = {
              			sex:'male',//sex defaults to male
              			age:18 //age defaults to 18
              		}
              		//The second Chinese writing method
              		//Adding static is to add properties and methods to the prototype object
              			//Limit the type and necessity of label attributes
              			static 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
              			static defaultProps = {
              				sex:'male',//sex defaults to male
              				age:18 //age defaults to 18
              			}
        

ref(dom node object)

  • ref in string form

    • Set ref:ref = "input2"
    • Get Ref: this refs
    • Not commonly used
  • Callback function setting ref

    • //The first method will be called repeatedly
      //Set ref
      <input ref={c => this.input1 = c } type="text" placeholder="Click the button to prompt data"/>&nbsp;
      //The second method will not be called repeatedly
      /*
      	saveInput = (c)=>{
      				this.input1 = c;
      				console.log('@',c);
      			}
      */
      //<input ref={this.saveInput} type="text"/><br/><br/>
      
      
  • createRef setting ref

    • //< input ref = {this. Myref} type = "text" placeholder = "click button to prompt data" / > & nbsp;
      //myRef = React.createRef()
      /*
      showData = ()=>{
      				alert(this.myRef.current.value);
      			}
      */
      

Function component

Function components only have props attributes, but you can use hooks to add attributes such as state

Limit props and set default props

//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>
				)
		}
		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
		}

Event handling in react

/* 
				(1).Specify the event handler through the onXxx attribute (note case)
						a.React Custom (composite) events are used instead of native DOM events -- for better compatibility
						b.React Events in are handled by event delegation (delegated to the outermost element of the component) -------------------------------------------------------------------------------------------------------------------------------
				(2).Via event Get the DOM element object of the event from target -- don't overuse ref
			 */

Higher order functions and corrilization of functions

//#region 
				/* 
					Higher order function: if a function conforms to any of the following two specifications, the function is a higher order function.
									1.If the parameter received by A function is A function, then A can be called A higher-order function.
									2.If the return value of A function call is still A function, then A can be called A higher-order function.
									Common high-order functions include Promise, setTimeout, arr.map(), and so on

					Coriolism of function: the function coding form of receiving parameters for many times and finally unified processing is realized by continuing to return the function through function call. 
						function sum(a){
							return(b)=>{
								return (c)=>{
									return a+b+c
								}
							}
						}
					*/
		//#endregion

Collect form data

Uncontrolled component, use and get now (use ref to get the value of input)

Controlled component (put Input value into state)

Implementation method:

Coritization using functions

//<input onChange={this.saveFormData('username')} type="text" name="username"/>
/*
//Save form data to status
			saveFormData = (dataType)=>{
				return (event)=>{
					this.setState({[dataType]:event.target.value})
				}
			}
*/

Curry implementation without function

//<input onChange={event => this.saveFormData('username',event) } type="text" name="username"/>
/*
	//Save form data to status
			saveFormData = (dataType,event)=>{
				this.setState({[dataType]:event.target.value})
			}
*/

About Diff algorithm

If you add a key to the tag, the diff algorithm will be used

diff algorithm will compare the new virtual DOM with the old virtual DOM to generate a real dom

	1. fictitious DOM in key Role of:
					1). Simply put: key It's virtual DOM Identification of the object, When updating the display key Plays an extremely important role.

					2). In detail: When the data in the state changes, react The new virtual data will be generated according to the new data DOM], 
												subsequently React Click new virtual DOM]And [old virtual machine] DOM]of diff The comparison rules are as follows:

									a. Old virtual DOM New virtual found in DOM same key: 
												(1).If virtual DOM The content in the has not changed, Real before direct use DOM
												(2).If virtual DOM The content has changed, Then a new reality is generated DOM,Then replace the previous real in the page DOM

									b. Old virtual DOM No connection to the new virtual machine was found in DOM same key
												Create new reality based on data DOM,Then render to the page
									
			2. use index As key Possible problems:
								1. If the data is added in reverse order, deleted in reverse order and other destructive operations:
												Will produce unnecessary truth DOM to update ==> The interface effect is OK, But the efficiency is low.

								2. If the structure also contains the name of the input class DOM: 
												Errors will occur DOM to update ==> There is a problem with the interface.
												
								3. be careful! If there are no operations that destroy the order, such as adding or deleting data in reverse order,
									For rendering only, list for presentation, use index As key There is no problem.
					
			3. How to choose in development key?:
								1.It is best to use the unique identification of each data as the key, such as id,The unique value of mobile phone number, ID card number, student ID number and so on.
								2.If you're sure it's just a simple display of data, use index It's OK.

Es6 extension

Extended operator

The extension operator cannot expand the properties of an object, but {... xx} can be used to generate a new object, and [... arr] can also generate a new array

{... xx,xx:xxx} when you can copy the attribute of an object, you can reassign an attribute

=====================Use react in scaffolding

How do child components pass data to parent components

  • VC & Delphi

    • The parent component passes a function to the child component, and the child component can call it

    • //App.jsx
      //The parent component defines the method, and then passes the method to the child component
      /*
      <Footer todos={todos} checkAllTodo={this.checkAllTodo} clearAllDone={this.clearAllDone}/>
      	//checkAllTodo For 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})
      	}
      */
      //Subcomponent call
      /*
      <input type="checkbox" onChange={this.handleCheckAll} checked={doneCount === total && total !== 0 ? true : false}/>
      	//Callback for selecting all checkbox es
      	handleCheckAll = (event)=>{
      		this.props.checkAllTodo(event.target.checked)
      	}
      */
      
  • Using message subscriptions and publications

    • This is not a method in react

    • Can be used in any component

    • //introduce
      import PubSub from 'pubsub-js'
      //Message subscription
      /*
      this.token = PubSub.subscribe('atguigu',(_,stateObj)=>{
      			this.setState(stateObj)
      		})
      */
      //News release
      /*
      PubSub.publish('atguigu',{isLoading:false,users:response.data.items})
      */
      //Unsubscribe from messages
      /*
      componentWillUnmount(){
      		PubSub.unsubscribe(this.token)
      	}
      */
      

Use of routing

Matching rule of route: after clicking a route link, the url address will change to the changed address, and then history will listen to the change of url address, and then go to app JSX matches the routing rules, displays the component after matching, and continues to match the routing rules in the component... So this is why exact cannot be used in the routing matching rules

  • Basic use

    • Routing link components such as link and navlink will be rendered as a tag

    • App.jsx
      //introduce
      import {Link,Route} from 'react-router-dom'
      {/* Switch components by routing links in React -- write routing links */}
      							<Link className="list-group-item" to="/about">About</Link>
      							<Link className="list-group-item" to="/home">Home</Link>
      {/* Register routing */}
      								<Route path="/about" component={About}/>
      								<Route path="/home" component={Home}/>
      index.js
      //Introducing react core library
      import React from 'react'
      //Introducing ReactDOM
      import ReactDOM from 'react-dom'
      //
      import {BrowserRouter} from 'react-router-dom'
      //Introduce App
      import App from './App'
      //Wrap < app / > with browserouter to ensure that the routing components use the same Router
      ReactDOM.render(
      	<BrowserRouter>
      		<App/>
      	</BrowserRouter>,
      	document.getElementById('root')
      )
      
  • NavLink

    • After clicking, the active class will be added to the current a tag by default

    • Modify the simulated class name and click add, activeClassName = "atguigu"

    • Encapsulate NavLink

      • MyNavLink
        /*
        <NavLink activeClassName="atguigu" className="list-group-item" {...this.props}/>
        */
        App.jsx
        //<MyNavLink to="/about">About</MyNavLink>
        
  • Use of switches

    • Without the Switch component, after matching the route, it will continue to match down

    • <Switch>
      									<Route path="/about" component={About}/>
      									<Route path="/home" component={Home}/>
      									<Route path="/home" component={Test}/>
      								</Switch>
      
  • Precise matching and fuzzy matching

    • The default route is fuzzy matching
    • Exact matching can be achieved by using exact in the Route tag
    • Accurate matching cannot be abused. If it is a secondary route, there will be problems using it
  • Redirect

    • If the route does not match, it will be redirected to the default route

    • <Switch>
      									<Route path="/about" component={About}/>
      									<Route path="/home" component={Home}/>
      									<Redirect to="/about"/>
      								</Switch>
      
  • Use of nested routes

  • Pass parameters (params,search,state), including programmed route navigation

    • Message Medium index.jsx
      import React, { Component } from 'react'
      import Detail from './Detail'
      import {Link, Route} from 'react-router-dom'
      import { countSubscriptions } from 'pubsub-js'
      
      export default class Message extends Component {
          state={
            messagedata:[
              {id:1,title:'Message 1'},
              {id:2,title:'Message 2'},
              {id:3,title:'Message 3'}
            ]
          }
          pushShow=(id,title)=>{
            // this.props.history.push(`/home/message/detail/${id}/${title}`)
            // this.props.history.push(`/home/message/detail?id=${id}&title=${title}`)
            this.props.history.push('/home/message/detail',{id,title})
          }
          replaceShow=(id,title)=>{
            // this.props.history.replace(`/home/message/detail/${id}/${title}`)
            this.props.history.replace(`/home/message/detail?id=${id}&title=${title}`)
            this.props.history.replace('/home/message/detail',{id,title})
          }
          back=()=>{
            this.props.history.goBack()
          }
          forward=()=>{
            this.props.history.goForward()
          }
          go=()=>{
            this.props.history.go(-2)
          }
          render() {
              return (
                  <ul>
                    {
                      this.state.messagedata.map(v=>{
                        return (
                          <li key={v.id}>
                            {/* params Transfer parameters */}
                            {/* <Link to={`/home/message/detail/${v.id}/${v.title}`}>{v.title}</Link> */}
                            {/* search Transfer parameters */}
                            {/* <Link to={`/home/message/detail?id=${v.id}&title=${v.title}`}>{v.title}</Link> */}
                            {/* state Transfer parameters */}
                            <Link to={{pathname:'/home/message/detail',state:{id:v.id,title:v.title}}}>{v.title}</Link>
                            <button onClick={()=>{this.pushShow(v.id,v.title)}}>pushShow</button>
                            <button onClick={()=>{this.replaceShow(v.id,v.title)}}>replaceShow</button>
                          </li>
                        )
                      })
                    }
                    <br/>
                    <div>
                      {/* prams Transfer parameters */}
                      {/* <Route path="/home/message/detail/:id/:title" component={Detail}></Route> */}
                      {/* search Transfer parameters */}
                      {/* <Route path="/home/message/detail" component={Detail}></Route> */}
                      {/* state Transfer parameters */}
                      <Route path="/home/message/detail" component={Detail}></Route>
                    </div>
                    <br/>
                    <div>
                      <button onClick={this.back}>back</button>
                      <button onClick={this.forward}>forward</button>
                      <button onClick={this.go}>go</button>
                    </div>
                  </ul>
              )
          }
      }
      //jsx in Detail in Message component
      import React, { Component } from 'react'
      import qs from 'querystring'
      
      export default class Detail extends Component {
          state={
              detaildata:[
                  {id:1,content:'111'},
                  {id:2,content:'222'},
                  {id:3,content:'333'}
              ]
          }
          render() {
              console.log(this.props)
              // Accept parameters passed by params
              // let {id,title}=this.props.match.params
              //Accept and process the parameters passed by search
              // let search=this.props.location.search.slice(1)
              // let {id,title}=qs.parse(search)
              //Accept parameters passed by state
              let {id,title}=this.props.location.state
              let obj=this.state.detaildata.find(v=>{
                  return v.id===parseInt(id)
              })
              return (
                  <div>
                      <ul>
                          <li>ID:{id}</li>
                          <li>TITLE:{title}</li>
                          <li>CONTENT:{obj.content}</li>
                      </ul>
                  </div>
              )
          }
      }
      
      
    • Since the params and search parameters are in the address bar, refreshing the page will certainly not cause data loss

    • The state parameter is stored in the history. Refreshing the page (BrowserRouter) will not cause data loss, and refreshing the page (HashRouter) will cause data loss

  • push and replace mode

    • The default is push mode
    • Using push will push a history in history
    • replace will not push a history
    • Using the replace mode, < mynavlink replace to = "/ about" > about < / mynavlink >
  • Use of withRouter

    • The information of histtory can be obtained from the routing component, but the properties cannot be passed to it
    • General components do not have a unique API in the routing component, such as obtaining history information
    • withRouter can process general components so that the general components have the unique API of routing components
    • export default withRouter(Header) returns a new component

About style loss

In index HTML to introduce the use of external styles/ When the url address is the url address of the nested route, the style may be lost after the page is refreshed

terms of settlement:

  • Use / xxx
  • Use% PUBLIC_URL%/xxxx
  • The HashRouter is used because the url address in the HashRouter contains #, and the server does not look at the address that # follows

Use of redux and react redux

redux is not in react. redux is a kind of state management. It can access the common attributes of components for easy management

Three important files: action, store and reducer

Note: the change of redux status will not lead to the update of components, so you should listen for the change of its status

  • Basic use
index.js
/*
store.subscribe(()=>{
	ReactDOM.render(<App/>,document.getElementById('root'))
})
*/
redux folder
store.js
/*
//createStore is introduced to create the most core store object in redux
import {createStore} from 'redux'
//Introduce reducer serving Count component
import countReducer from './count_reducer'
//Expose store
export default createStore(countReducer)
*/
count_reducer.js
/*
const initState = 0 //Initialization status
export default function countReducer(preState=initState,action){
	// console.log(preState);
	//Get: type, data from the action object
	const {type,data} = action
	//Determine how to process data according to type
	switch (type) {
		case 'increment': //If it's plus
			return preState + data
		case 'decrement': //If it is minus
			return preState - data
		default:
			return preState
	}
}
*/
Count Under folder
index.jsx
//import store from '../../redux/store'
//Get the state in the store
//<h1>The current summation is: {store. Getstate()}</h1>
/*
	//Update state in store
	//addition
	increment = ()=>{
		const {value} = this.selectNumber
		store.dispatch({type:'increment',data:value*1})
	}
*/
  • Optimization (using common variables, put the method of generating action into action.js)

    redux folder
    constant.js
    /* 
    This module is used to define the constant value of type in the action object. It has only one purpose: to facilitate management and prevent programmers from writing wrong words
    */
    export const INCREMENT = 'increment'
    export const DECREMENT = 'decrement'
    count_action.js
    /* 
    This file is dedicated to generating action objects for the Count component
    */
    import {INCREMENT,DECREMENT} from './constant'
    export const createIncrementAction = data => ({type:INCREMENT,data})
    export const createDecrementAction = data => ({type:DECREMENT,data})
    count_reducer.js
    /* 
    	1.This file is used to create a reducer serving the Count component. The essence of the reducer is a function
    	2.reducer The function receives two parameters: the previous state and the action object
    */
    import {INCREMENT,DECREMENT} from './constant'
    
    const initState = 0 //Initialization status
    export default function countReducer(preState=initState,action){
    	// console.log(preState);
    	//Get: type, data from the action object
    	const {type,data} = action
    	//Determine how to process data according to type
    	switch (type) {
    		case INCREMENT: //If it's plus
    			return preState + data
    		case DECREMENT: //If it is minus
    			return preState - data
    		default:
    			return preState
    	}
    }
    Count Under folder
    index.jsx
    	//addition
    	increment = ()=>{
    		const {value} = this.selectNumber
    		store.dispatch(createIncrementAction(value*1))
    	}
    
  • How to change the state in the store asynchronously

    • Modify the state in the store in the asynchronous code of the component

      • 	Count Under folder
            index.jsx
            //Asynchronous addition
        	incrementAsync = ()=>{
        		const {value} = this.selectNumber
        		setTimeout(()=>{
        			store.dispatch(createIncrementAction(value*1))
        		},500)
        	}
        
    • Use functional action

      • Count Under folder
        index.jsx
        //Asynchronous addition
        	incrementAsync = ()=>{
        		const {value} = this.selectNumber
        		// setTimeout(()=>{
        			store.dispatch(createIncrementAsyncAction(value*1,500))
        		// },500)
        	}
        redux Under folder
        count_action.js
        //Asynchronous action means that the value of action is a function. Synchronous action is generally called in asynchronous action. Asynchronous action is not necessary.
        export const createIncrementAsyncAction = (data,time) => {
        	return (dispatch)=>{
        		setTimeout(()=>{
        			dispatch(createIncrementAction(data))
        		},time)
        	}
        }
        redux folder
        store.js
        //Redux thunk is introduced to support asynchronous action s
        import thunk from 'redux-thunk'
        //Expose store
        export default createStore(countReducer,applyMiddleware(thunk))
        

======================================================

The above only uses redux. Each component can operate the state of the store, which is inconvenient to manage, so react Redux is also used

In react Redux, only the container component can operate on the state in sotre. Its ui component cannot, but can only rely on the container component to pass the state attribute and modify the state callback function

  • Basic use of react Redux

    • containers Under folder
      //Represents the container component
      Count Under folder
      index.jsx
      //UI component of Count
      import CountUI from '../../components/Count'
      //Introduce action
      import {
      	createIncrementAction,
      	createDecrementAction,
      	createIncrementAsyncAction
      } from '../../redux/count_action'
      
      //Connect is introduced to connect UI components with redux
      import {connect} from 'react-redux'
      
      /* 
      	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)
      components folder
      Count Under folder
      //Represents a ui component
      index.jsx
      //obtain
      <h1>The current summation is:{this.props.count}</h1>
      //modify
      //Odd plus
      	incrementIfOdd = ()=>{
      		const {value} = this.selectNumber
      		if(this.props.count % 2 !== 0){
      			this.props.jia(value*1)
      		}
      	}
      	//Asynchronous addition
      	incrementAsync = ()=>{
      		const {value} = this.selectNumber
      		this.props.jiaAsync(value*1,500)
      	}
          App.jsx
      import React, { Component } from 'react'
      import Count from './containers/Count'
      import store from './redux/store'
      
      export default class App extends Component {
      	render() {
      		return (
      			<div>
      				{/* Pass store to container component */}
      				<Count store={store} />
      			</div>
      		)
      	}
      }
      

There is only one reducer in the above store, which is directly added with createstore (countreducer, applymeddleware (thunk)), so that the state in the store is a single attribute, not an object, and can be obtained directly

  • Optimal use of react Redux

    • Adding react Redux does not require us to manually subscribe to the state change information in sotre. Adding a Provider can pass the store to multiple container objects at one time, write the container object and ui object together, mapDispatchToProps can be an object, and then directly pass the method of generating action to the ui object, React Redux will automatically submit the action generated by the ui object to the store

    • 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(
      	<Provider store={store}>
      		<App/>
      	</Provider>,
      	document.getElementById('root')
      )
      containers Under folder
      Count folder
      index.jsx
      //Use connect()() to create and expose a container component of Count
      export default connect(
      	state => ({count:state}),
      
      	//General writing of mapDispatchToProps
      	/* dispatch => ({
      		jia:number => dispatch(createIncrementAction(number)),
      		jian:number => dispatch(createDecrementAction(number)),
      		jiaAsync:(number,time) => dispatch(createIncrementAsyncAction(number,time)),
      	}) */
      
      	//Short for mapDispatchToProps
      	{
      		jia:createIncrementAction,
      		jian:createDecrementAction,
      		jiaAsync:createIncrementAsyncAction,
      	}
      )(Count)
      
  • Multiple container components for data sharing

    • The state in the store is an object, and the default attribute value in the object is provided by its corresponding reducer

    • containers folder
      Count/index.jsx
      //Use connect()() to create and expose a container component of Count
      export default connect(
      	state => ({
      		count:state.he,
      		renshu:state.rens.length
      	}),
      	{
      		jia:createIncrementAction,
      		jian:createDecrementAction,
      		jiaAsync:createIncrementAsyncAction,
      	}
      )(Count)
      Person/index.jsx
      export default connect(
      	state => ({yiduiren:state.rens,he:state.he}),//Mapping state
      	{jiaYiRen:createAddPersonAction}//Method of mapping operation state
      )(Person)
      redux folder
      actions/person.js
      import {ADD_PERSON} from '../constant'
      
      //Create an action object to add a person
      export const createAddPersonAction = personObj => ({type:ADD_PERSON,data:personObj})
      reducers/person.js
      import {ADD_PERSON} from '../constant'
      reducers/person.js
      //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
      			return [data,...preState]
      		default:
      			return preState
      	}
      }
      store.js
      //createStore is introduced to create the most core store object in redux
      import {createStore,applyMiddleware,combineReducers} from 'redux'
      //Introduce reducer serving Count component
      import countReducer from './reducers/count'
      //Introduce reducer serving Count component
      import personReducer from './reducers/person'
      //Redux thunk is introduced to support asynchronous action s
      import thunk from 'redux-thunk'
      
      //Summarize all reducers to become a total reducer
      const allReducer = combineReducers({
      	he:countReducer,
      	rens:personReducer
      })
      
      //Expose store
      export default createStore(allReducer,applyMiddleware(thunk))
      App.jsx
      import React, { Component } from 'react'
      import Count from './containers/Count'
      import Person from './containers/Person'
      
      export default class App extends Component {
      	render() {
      		return (
      			<div>
      				<Count/>
      				<hr/>
      				<Person/>
      			</div>
      		)
      	}
      }
      
      

Note that if the preState in reducer is an array or object, it is necessary to return a new array or object, because redux will compare the addresses of the two. If the address remains unchanged, the change is invalid

  • Use the react Redux developer tool to monitor state changes in the store

    • redux/store.js
      import {composeWithDevTools} from 'redux-devtools-extension'
      export default createStore(allReducer,composeWithDevTools(applyMiddleware(thunk)))
      

Keywords: Front-end React

Added by Simsonite on Thu, 23 Dec 2021 09:28:35 +0200