React基础-组件生命周期&diffing

60 阅读3分钟

非受控组件

数据随用随取, 输入类的数据没有被state维护
    

受控组件

输入类的数据被state维护, 能省略掉ref

高阶函数

符合下面任意一条就能被称为高阶函数
    1. 若函数A, 接收的是一个函数, 那么这个函数A就可以称为高阶函数
    2. 若函数A, 调用的返回值依然是一个函数, 那么A也可以被称为高阶函数
    
常见的高阶函数: 
    promise, setTimeout, array很多的操作

函数的柯理化

    通过函数调用继续返回函数的方式, 实现多次接受参数最终统一处理的函数编码形式

save = (data) => {
    // 这么写的时候, 当使用 this.save('userName')调用 只会输出 字符串 userName
    console.log(data) 
}

// 这么写的意思是 将save函数交给onChange回调
<input onChange={this.save} />

// 这么写的意思是将save()函数的返回值交给 onChange 进行回调
<input onChange={this.save('userName')} />

// 将save这么改造之后,  内部返回的是一个函数, event 是event, data 则是字符串userName
save = (data) => {
    // 这个data 是函数传递的字符串
    console.log(data)
    // 这个函数是被 onChanged调用
    return (event) => {
        console.log(event.target.value)
    }
}

save = (dataType) => {
    return (event) => {
        // 这里注意 不能直接写dataType:event.target.value
        // 加[] 意思是读取 dataType这个变量, 而不是把他当做字符串
        this.setState({[dataType]:event.target.value})
    }
}

当到真正使用的时候, 直接去state里取就可以了
const { uname, pwd } = this.state

组件的生命周期

<script type="text/babel">
        // 1. 创建class组件
        class Dom extends React.Component {

            state = {opacity:1}

            componentDidMount() {
                // 组件挂载的时候 开启计时器
                this.timer = setInterval(() => {
                    let {opacity} = this.state
                    opacity -= 0.1
                    if(opacity <= 0) opacity = 1
                    this.setState({opacity})
                }, 200)

            }

            componentWillUnmount() {
                // 组件卸载的时候清除计时器,  也叫生命周期钩子函数
                clearInterval(this.timer)
            }

            removeH1 = () => {
                // 卸载组件
                ReactDOM.unmountComponentAtNode(document.getElementById('app1'))
            }

            render() {
                return (
                    <div>
                    <h1 style={{opacity:this.state.opacity}}>test react 声明周期</h1>
                <button onClick={this.removeH1}>点击</button>
                    </div>
                )
                
            }
        }
       

        ReactDOM.render(<Dom  />, document.getElementById('app1'))

    </script>

完整的生命周期(旧版本)

image.png

上图中父组件有三条线
    从上到下
    setState() 触发 shouldComponentUpdate 的更新 这个函数默认返回true
    forceUpdate() 触发 componentWillUpdate, 不会收到上面shouldComponentUpdate影响
    
1. 初始化阶段: 由ReactDOM.render()触发 --- 初次
    constructor()
    componentWillMount()
    render()
    componentDidMount()
2. 更新阶段: 由组件内部的setState或者父组件render触发
    shouldComponentUpdate()
    componentWillUpdate()
    render()
    componentDidUpdate()
3. 卸载组件: 由ReactDOM.unmountComponentAtNode()触发
    componentWillUnmount()
    
    

新版本的生命周期

image.png

1. 初始阶段
    constructor() 
    // state的值, 任何时候都取决于props 可以重写这个函数
    static getDerivedStateFromProps(props, state) -- 几乎不怎么用, 必须返回state对象或者null
    render()
    componentDidMount()
2. 更新阶段
    static getDerivedStateFromProps()
    souldComponentUpdate()
    redner()
    getSnapshotBeforeUpdate(preProps, preState) -- 几乎不怎么用, 相当于是更新前的状态
    componentDidUpdate(preProps, preState, snapShot) -- snapShot 就是 上面那个方法 return出来的
3. 卸载组件
    componentWillUnmount()

diffing算法

react 中的key有什么作用? 
    首先, key是虚拟DOM对象的标识, 在更新显示时起着重要的作用
    其次, 当状态中的数据发生变化时, react会根据新数据生成新的虚拟DOM, 随后会拿新旧进行比较
        1. 旧虚拟DOM中找到了与新虚拟DOM相同的key
            . 若虚拟DOM中的内容没有改变, 直接使用之前的真实DOM
            . 若虚拟DOM中的内容改变了, 则生成新的真实DOM, 随后替换掉页面中之前的真实DOM
        2. 旧虚拟DOM中未找到与新虚拟DOM相同的key
            根据数据创建新的真实DOM, 随后渲染到页面上
            
为什么遍历的时候不要用index作为key?
    1. 若对数据进行: 逆序添加, 删除, 等破坏顺序操作, 会产生没有必要的真实DOM更新(界面没问题但效率低)
    2. 如果结构中还包含输入类的DOM, 会产生错误DOM更新
    3. 如果不存在对数据的逆序添加, 删除等破坏顺序的操作, 只用于渲染列表展示, 这个时候是没问题的
    
那开发中如果选择key?
    1. 最好使用每条数据的唯一标识作为key
    2. 如果确定只是简单的展示数据, 用index也是可以的
    

一旦含有input输入框的, 有输入内容, 就容易出现内容混乱
<li key=index> {obj.name} <input type="text"></li>