react组件02

时间:2024-11-08 09:55:12
setState
setState用法

可以传入一个对象,也可以传入一个函数,,
setState是异步的,会将对象加入一个队列,在一定的时间之后进行统一渲染,,,所以多次调用setState去累加某一个值,是会有问题的

如果想获取异步之后的值,有第二个参数,传入一个函数,获取渲染后的值

  this.setState({count:this.state.count+1},(res)=>{
            console.log(res,"res")
        })

当然也可以在生命周期函数 componentDidUpdate(prevProps,prevState,snapshot)

如果想获取每次setState设置的状态值,,可以传入一个函数,获取上一个状态的state和props:

    changeCount(){
        /**
         * setState 是异步的,, 如果想要获取上一次state的状态
         *  上一个state,,, 可以在,上一个state的状态修改,,
         *  返回一个对象,,和之前的state合并,, 合并使用 Object.assign
         */
        this.setState((prevState,prevProps)=>{
            console.log(prevState.count)
            return {
                count:prevState.count+1
            }
        })

        this.setState((prevState,prevProps)=>{
            console.log(prevState.count)
            return {
                count:prevState.count+1
            }
        })
        
    }

在react18之后 setState是异步的,在react18之前,在react的事件中,setState是异步的,在原生DOM事件中,比如addEventListener或者setTimeout中是同步的

在react18之后,默认所有的操作都放到了批处理中,,, 异步批渲染
如果希望代码同步,,,可以使用 flushSync

import {flushSync} from "react-dom";
flushSync(()=>{
    // 同步代码
    this.setState({
        count:11
    })
})
console.log(this.state.count)

SCU

SCU: shouldComponentUpdate
默认继承react的Component类实现的组件,,在更新的时候,不管是否有改动,都会全部更新,,
shouldComponentUpdate 可以先浅层比较传入对象是否相同,相同就不去渲染,不相同再渲染。。。。
PureComponent是实现了这个SCU的组件,一般使用这个

react更新流程
  1. props/state改变
  2. render函数重新执行
  3. 产生新的dom树
  4. 进行diff算法
  5. 计算出差异,进行更新

这个diff算法最终被优化成了:

  • 同层节点之间相互比较,不回跨节点比较
  • 不同类型的节点,产生不同的树结构
  • 开发中,可以通过key,来指定哪些节点在不同的渲染下保持稳定
shouldComponentUpdate

生命周期钩子

sholdComponentUpdate((nextProps,nextState)=>{
    // 返回true, 调用render
    // 返回false   不调用
})

类组件继承PureComponent可以自己比较
函数组件需要使用一个高阶函数 memo 进行包裹,,
高阶函数就是,传入一个组件,返回一个新的组件,,,对原来组件的增强

memo(function (){ 
    return "xx"
})
不可变数据的力量

react组件中,,state中的数据,是不可变的,,不要去随意改变state中的数据,,而是浅拷贝一个新的值,修改之后去赋值
如果你直接修改state中的某个对象,,但是PureComponent或者Memo的浅层比较是发现不了对象底层数据变化的,
只能通过赋值一个新的对象,进行改变

ref使用

this.refs.名字
class App extends PureComponent {

    componentDidMount() {
        this.refs.hehe.printHehe()
    }

    render() {
        return (
            <div>
                <Hehe ref="hehe"/>
            </div>
        );
    }
}

createRef 函数
import React, { createRef, PureComponent} from 'react';
import Hehe from "./Hehe";

class App extends PureComponent {

    componentDidMount() {
        console.log(this.HeheRef)
        this.HeheRef.current.printHehe()
    }


    constructor() {
        super();
        this.HeheRef = createRef()
    }

    render() {
        return (
            <div>
                <Hehe ref={this.HeheRef}/>
            </div>
        );
    }
}

export default App;

传入一个箭头函数,,函数的参数就是 当前ref本身,
import React, { createRef, PureComponent} from 'react';
import Hehe from "./Hehe";

class App extends PureComponent {

    componentDidMount() {
        this.heheRef.printHehe()
    }


    constructor() {
        super();
       this.heheRef = null
    }

    render() {
        return (
            <div>
                <Hehe ref={(result)=>this.heheRef = result}/>
            </div>
        );
    }
}

export default App;

函数式组件没有实例,无法通过ref获取他们的实例。但是某些时候,我们想获取函数式组件内的某个DOM,,
可以将ref传递进去

import {forwardRef} from "react";

const HelloWorld = forwardRef(function(props,ref){

    return (
        <div>
            <h2 ref={ref}>hello word</h2>
        </div>
    )
})


export default HelloWorld

import React, { createRef, PureComponent} from 'react';
import Hehe from "./Hehe";
import HelloWorld from "./HelloWorld";

class App extends PureComponent {

    componentDidMount() {
        this.heheRef.printHehe()
        console.log(this.hellowordRef.current)
    }


    constructor() {
        super();
       this.heheRef = null
        this.hellowordRef = createRef()
    }

    render() {
        return (
            <div>
                <Hehe ref={(result)=>this.heheRef = result}/>
                <HelloWorld  ref={this.hellowordRef}/>
            </div>
        );
    }
}

export default App;

受控组件

受控组件: 受react控制的组件,,如果绑定了react的state,就被react控制了,需要通过onChange去改变这个input的值。。
react中,state属性,只能通过setState来更新
非受控组件: 没有被react控制的组件,,使用defaultValue设置默认值,,用原生的方式去获取数据

js表单控件改变会掺入一个event,, event.target就是这个控件,, 设置state的时候,可以写成:

// 通过 event.target.type 先判断一个是否是 checkbox  或者是 radio,,
// 因为这两个控件的值,,在event.target.checked 上
this.setState({
    [event.state.name]:event.state.value
})

checkbox的多选,和 select的多选

高阶组件

高阶函数
  • 接受一个或者多个函数作为输入
  • 或者 返回一个函数
    比如 : map ,filter,reduce
高阶组件 higher order components

高阶组件,本身不是一个组件,是一个函数,,并且这个函数的参数是另一个组件,,返回值也是一个组件

props增强
有时候多个组件会共用属性,,但是每一个去使用 <Context.Consumer> 代码会很冗余,,在高阶函数中处理这些共用的属性

import React from "react";

const UserContext = React.createContext()


export default UserContext

import UserContext from "../context/user-context";

function enhancerProps(OriginComponent){

    // 内部是另一个组件 === props是父组件传过来的props
    return (props)=>{
        return (
            <UserContext.Consumer>
                { value => <OriginComponent {...props} {...value} />}
            </UserContext.Consumer>
        )
    }


}


export default enhancerProps

import React, { PureComponent} from 'react';
import HelloWorld from "./HelloWorld";
import UserContext from "./context/user-context";

class App extends PureComponent {
    constructor() {
        super();
        this.state = {
            userInfo:{
                username:"cc",
                age:11
            }
        }
    }
    render() {
        return (
            <div>
                <UserContext.Provider value={this.state.userInfo}>
                    <HelloWorld address="成都"/>
                </UserContext.Provider>

            </div>
        );
    }
}

export default App;

import React, {PureComponent} from 'react';
import enhancerProps from "./hoc/enhancerProps";
import UserContext from "./context/user-context";

class HelloWorld extends PureComponent {
    render() {
        return (
            <div>
                {/*<UserContext.Consumer>*/}
                {/*    { value=> <h3>{value.username}</h3>}*/}
                {/*</UserContext.Consumer>*/}

                { this.props.username} - {this.props.age} --{this.props.address}
            </div>
        );
    }
}

export default enhancerProps(HelloWorld);

判断是否登录,,或者判断数据是否为空,展示提示
写在高阶组件里面
这个状态改变之后,是根据localStorage中的判断的,没有设置setState,也就没有执行render,,
this.forceUpdate() 强制更新

生命周期劫持
比如判断某个组件的加载时间,在钩子函数 UNSAFE_componentWillMountcomponentDidMount 记录时间差
显示组件的加载时间

Hook可以替代HOC

portals使用

portals: 大门
react中会设置一个根组件,下面的子元素默认都是在这个根组件下面的,,, 在处理,对话框,提示框,固定定位元素的时候非常有用

import {createPortal} from "react-dom";
// 将第一个参数传入的节点,放入指定的DOM中
{createPortal(<div>hehe123</div>,document.querySelector("#other"))}
Fragment

类似于vue中的 template,。。。

 <Fragment></Fragment>
react中的严格模式
// 被strictMode 标签包裹就会使用严格模式
 <StrictMode>
    <App/>
</StrictMode>