React system study notes--super basic--super detailed--super concise--React expansion (8)

1 setState

Two ways of writing setState to update the state

setState(stateChange, [callback])------object-style setState

stateChange is a state change object (the object can reflect the state change) (state update is asynchronous)

callback is an optional callback function, which is called after the state is updated and the interface is updated (after render is called)

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, which is called after the state is updated and the interface is updated (after render is called)

Summarize

Object-style setState is shorthand for functional-style setState ( 语法糖)

Principles of use:

If the new state does not depend on the original state => use the object method

If the new state depends on the original state => use the function method

If you need to get the latest state data after setState() is executed, read it in the second callback function

import React, {
    
     Component } from 'react'
export default class Demo extends Component {
    
    
state = {
    
     count: 0 }
add = () => {
    
    
//对象式的setState
/* //1.获取原来的count值
const {count} = this.state
//2.更新状态
this.setState({count:count+1},()=>{ console.log(this.state.count); })
//console.log('12行的输出',this.state.count); //0 */
//函数式的setState
this.setState(state => ({
    
     count: state.count + 1 }))
}
render() {
    
    
return (
<div>
  <h1>当前求和为:{
    
    this.state.count}</h1>
  <button onClick={
    
    this.add}>点我+1</button>
</div>
)}}

2 lazyLoad

lazyLoad of routing components

Components in lazy loading can be adjusted as they are used, and will not be loaded in advance

When using lazy loading, one needs to be given fallback, which is used to display when the request is too slow or the component cannot be requested, usually 组件(or directly 虚拟DOM)

fallbackIf it is specified as a component, the component must not be specified as 懒加载组件a normal imported component.

//实现路由懒加载需要lazy函数和Suspense内置组件
import React,{
    
     Component,lazy,Suspense } from 'react' 
//现在不能直接这样引入组件
//import Home from './Home'
//import About from './About'
//1 需要这样引入
const Home = lazy(()=> import './Home')
const About = lazy(()=> import './About')

//2.通过<Suspense>指定在加载得到路由打包文件前显示一个自定义loading界面
//这样的虚拟dom也可以
<Suspense fallback={
    
    <h1>loading.....</h1>}>
//<Suspense fallback={<Loading/>}>   指定为组件,此时Loading组件不能用懒加载形式引入,不然死循环                 
    <Switch>
        <Route path="/xxx" component={
    
    Xxxx}/>
        <Redirect to="/login"/>
    </Switch>
</Suspense>

3 Hooks

What are React Hooks/Hooks?

Hook is a new feature/new syntax added to React 16.8.0

Allows you to use state and other React features in functional components

Three commonly used Hooks

State Hook:React.useState()

Effect Hook:React.useEffect()

Ref Hook:React.useRef()

State Hook

State Hook allows function components to also have a state state, and perform read and write operations on state data

Syntax: const [xxx, setXxx] = React.useState(initValue)

useState() Description

  • Parameters: The value specified for the first initialization is cached internally
  • Return value: an array containing 2 elements, the first is the internal current state value, and the second is a function to update the state value

setXxx() 2 ways of writing

  • setXxx(newValue):: The parameter is a non-function value, directly specify the new state value, and use it internally to overwrite the original state value

  • setXxx(value => newValue): The parameter is a function, which receives the original state value and returns the new state value, which is used internally to overwrite the original state value

Effect Hook

Effect Hook allows you to perform side effects in function components (for simulating lifecycle hooks in class components)

Side-effect operations in React:

  • Send ajax request data acquisition
  • Set Subscription/Start Timer
  • Manually change the real DOM

Grammar and Description

React.useEffect(() => {
    
     
  // 在此可以执行任何带副作用操作
  return () => {
    
     // 在组件卸载前执行,将要卸载
    // 在此做一些收尾工作, 比如清除定时器/取消订阅等
  }
}, [stateValue]) 
// 第二个参数不写,就是监测所有人,只要某个状态改变就调用这个函数,写空数组就是谁都不检测,数组写值就是指定监测

You can think of useEffect Hook as a combination of the following three functions

componentDidMount()//第二个参数写空数组,谁都不监测
componentDidUpdate()//不写第二个参数,监测所有人
componentWillUnmount() //函数返回另外一个函数

Ref Hook

Ref Hook can store/find tags or any other data in the component in the function component

Syntax: const refContainer = useRef()

Function: save the label object, the function is the same as React.createRef()

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

4 Fragment

Function: It is not necessary to have a real DOM root tag (somewhat similar to the template in vue?)

When you have to use one 容器to wrap the dom element – ​​jsx syntax requirements, in the past we used to directly wrap a layerdiv

FragmentIt can be used 取代div, but it will be discarded by react after compilation, so it will not cause unnecessary hierarchical nesting

The effect is equivalent to writing one directly 空标签<></>, but there is a difference between the two

区别: FragmentYou can add keyattributes as unique identifiers (only key attributes), and empty tags cannot add any attributes

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 method between components, often used for communication between [ancestor components] and [descendant components]

  1. Create a Context container object
const XxxContext = React.createContext()  
  1. When rendering a subgroup, wrap it outside xxxContext.Providerand pass data to the descendant components through the value attribute
<xxxContext.Provider value={
    
    数据}>
		子组件
 </xxxContext.Provider>
  1. The descendant component reads the data:两种方法
//第一种方式:仅适用于类组件 
static contextType = xxxContext  // 声明接收context
this.context // 读取context中的value数据

//第二种方式: 函数组件与类组件都可以
<xxxContext.Consumer>
  {
    
    
    value => ( // value就是context中的value数据
      要显示的内容
    )
  }
</xxxContext.Consumer>

Note: In application development 一般不用context, its packaged react plugin is generally used

Full example:

//------------------- 完整例子 ------------------------------------------------
import React, {
    
     Component } from 'react'
import './index.css'
//创建Context对象
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>我是A组件</h3>
				<h4>我的用户名是:{
    
    username}</h4>
				<Provider value={
    
    {
    
    username,age}}>
					<B/>
				</Provider>
			</div>
		)
	}
}

class B extends Component {
    
    
	render() {
    
    
		return (
			<div className="child">
				<h3>我是B组件</h3>
				<C/>
			</div>
		)
	}
}

/* class C extends Component {
	//声明接收context
	static contextType = MyContext
	render() {
		const {username,age} = this.context
		return (
			<div className="grand">
				<h3>我是C组件</h3>
				<h4>我从A组件接收到的用户名:{username},年龄是{age}</h4>
			</div>
		)
	}
} */

function C(){
    
    
	return (
		<div className="grand">
			<h3>我是C组件</h3>
			<h4>我从A组件接收到的用户名:
			<Consumer>
				{
    
    value => `${
      
      value.username},年龄是${
      
      value.age}`} //也可以返回标签
			</Consumer>
			</h4>
		</div>
	)
}

6 Component optimization –PureComponent

2 problems with Component

As long as setState() is executed, even if the state data is not changed, the component will re-render() ==> low efficiency

Only the current component re-render() will automatically re-render the sub-component, even if the sub-component does not use any data of the parent component ==> low efficiency

Efficient practice

Only re-render() when the component's state or props data changes

Cause analysis

shouldComponentUpdate() in Component always returns true

Optimized solution

Method 1

重写shouldComponentUpdate()method

Compare the old and new state or props data, return true if there is a change, and return false if there is no change

Method 2

usePureComponent

PureComponent rewrites shouldComponentUpdate(), and returns true only if the state or props data changes

Notice:

Only for state and props data 浅比较, if only the internal data of the data object has changed, return false

Do not directly modify the state data, but to产生新数据

Projects generally use PureComponent to optimize

Optimize code example

import React, {
    
     PureComponent } from 'react'
import './index.css'
export default class Parent extends PureComponent {
    
    
state = {
    
     carName: "奔驰c36", stus: ['小张', '小李', '小王'] }
addStu = () => {
    
    
/* const {stus} = this.state
stus.unshift('小刘')
this.setState({stus}) */
const {
    
     stus } = this.state
this.setState({
    
     stus: ['小刘', ...stus] })
}

changeCar = () => {
    
    
//this.setState({carName:'迈巴赫'})

const obj = this.state
obj.carName = '迈巴赫'
console.log(obj === this.state);
this.setState(obj)
}

/* shouldComponentUpdate(nextProps,nextState){
// console.log(this.props,this.state); //目前的props和state
// console.log(nextProps,nextState); //接下要变化的目标props,目标state
return !this.state.carName === nextState.carName
} */

render() {
    
    
console.log('Parent---render');
const {
    
     carName } = this.state
return (
 <div className="parent">
   <h3>我是Parent组件</h3>
   {
    
    this.state.stus}&nbsp;
   <span>我的车名字是:{
    
    carName}</span><br />
   <button onClick={
    
    this.changeCar}>点我换车</button>
   <button onClick={
    
    this.addStu}>添加一个小刘</button>
   <Child carName="奥拓" />
 </div>
)
}
}

class Child extends PureComponent {
    
    
/* shouldComponentUpdate(nextProps,nextState){
console.log(this.props,this.state); //目前的props和state
console.log(nextProps,nextState); //接下要变化的目标props,目标state
return !this.props.carName === nextProps.carName
} */
render() {
    
    
console.log('Child---render');
return (
 <div className="child">
   <h3>我是Child组件</h3>
   <span>我接到的车是:{
    
    this.props.carName}</span>
 </div>
)
}
}

7 render props—similar to vue slots

How to dynamically pass in a structure (label) with content inside the component?

The slot technology is used in Vue, that is, the structure is passed in through the component tag body

During React

  • Use children props: pass in the structure through the component tag body
  • Use render props: pass in the structure through the component tag attribute, and can carry data, generally use the render function attribute

children props

  <A>
    <B>xxxx</B>
  </A>
  {
    
    this.props.children}
  问题: 如果B组件需要A组件内的数据, ==> 做不到 

render props

  <A render={
    
    (data) => <C data={
    
    data}></C>}></A>
  A组件: {
    
    this.props.render(内部state数据)}
  C组件: 读取A组件传入的数据显示 {
    
    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>我是Parent组件</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>我是A组件</h3>
  				{
    
    this.props.render(name)}
  			</div>
  		)
  	}
  }

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

8 Error Boundary

understand

​ Error boundary: used to capture errors in descendant components, render an alternate page, and write on the parent component

features

只能捕获后代组件生命周期​Errors generated 不能捕获自己组件errors generated and errors generated by other components in synthetic events, timers

getDerivedStateFromError配合componentDidCatch

  // 生命周期函数,一旦后台组件报错,就会触发
  static getDerivedStateFromError(error) {
    
    
      console.log(error);
      // 在render之前触发
      // 返回新的state
      return {
    
    
          hasError: true,
      };
  }

  componentDidCatch(error, info) {
    
    
      // 统计页面的错误。发送请求发送到后台去
      console.log(error, info);
  }

code example

  import React, {
    
     Component } from 'react'
  import Child from './Child'

  export default class Parent extends Component {
    
    

    state = {
    
    
      hasError: '' //用于标识子组件是否产生错误
    }

    //当Parent的子组件出现报错时候,会触发getDerivedStateFromError调用,并携带错误信息
    static getDerivedStateFromError(error) {
    
    
      console.log('@@@', error);
      return {
    
     hasError: error }
    }

    componentDidCatch() {
    
    
      console.log('此处统计错误,反馈给服务器,用于通知编码人员进行bug的解决');
    }

    render() {
    
    
      return (
        <div>
          <h2>我是Parent组件</h2>
          {
    
    this.state.hasError ? <h2>当前网络不稳定,稍后再试</h2> : <Child />}
        </div>
      )
    }
  }

9 Summary of Component Communication Methods

relationship between components

  • parent-child component
  • Sibling components (non-nested components)
  • Grandchildren components (cross-level components)

Several communication methods:

- props:
     1).children props
     (2).render props

- 消息订阅-发布:
     ubs-sub、event等等

- 集中式管理:
     edux、dva等等

- conText:
     产者-消费者模式

better match

- 父子组件:props
- 兄弟组件:消息订阅-发布、集中式管理
- 祖孙组件(跨级组件):消息订阅-发布、集中式管理、conText(开发用的少,封装插件用的多)

Guess you like

Origin blog.csdn.net/m0_55644132/article/details/127920196