React 面向组件编程(下)

文章目录

  • 前言
  • 一,受控组件与非受控组件
    • 1.受控组件
    • 2.非受控组件
    • 3.使用组件建议
  • 二,React生命周期
    • 1.旧版生命周期
    • 2.新版生命周期
  • 三,高阶函数和函数柯里化的理解
    • 1.高阶函数
    • 2.函数柯里化
    • 3.使用函数柯里化实例
    • 4.不使用函数柯里化
  • 总结

前言

  • 上一篇文章我们说了React面向组件编程的组件的基本使用和理解还有组件的三大核心属性,本节给大家讲解的是React 的生命周期,受控组件与非受控组件,高阶函数和函数柯里化的理解

一,受控组件与非受控组件

“受控”与“非受控”两个概念,区别在于这个组件的状态是否可以被外部修改。
一个设计得当的组件应该同时支持“受控”与“非受控”两种形式,即当开发者不控制组件属性时,组件自己管理状态,而当开发者控制组件属性时,组件该由属性控制。
而开发一个复杂组件更需要注意这点,以避免只有部分属性受控,使其变成一个半受控组件。

1.受控组件

  • 在HTML的表单元素中,它们通常自己维护一套state,并随着用户的输入自己进行UI上的更新,这种行为是不被我们程序所管控的。而如果将React里的state属性和表单元素的值建立依赖关系,再通过onChange事件与setState()结合更新state属性,就能达到控制用户输入过程中表单发生的操作。被React以这种方式控制取值的表单输入元素就叫做受控组件
<script type="text/babel">
        // 受控组件
        class Login extends React.Component {
            state = {
                username: '',//用户名称
                password: ''//用户密码
            }
            // 保存用户名在状态中
            saveUsername = (e) => {
                this.setState({ username: e.target.value })
            }
            // 保存密码在状态中
            savePassword = (e) => {
                console.log(e.target)
                this.setState({ password: e.target.value })
            }
            btnSub = (e) => {
                e.preventDefault()
                console.log(e)
                let { username, password } = this.state
                alert(`你输入的用户名是${username},密码是${password}`)
            }

            render() {
                return (
                    <div>
                        <form onSubmit={this.btnSub}>
                            账号:<input type="text" onChange={this.saveUsername} placeholder="输入数据" name='username' />
                            密码:<input type="text" onChange={this.savePassword} placeholder="输入密码" name='password' />
                            <button type="submit">点击登录</button>
                        </form>
                    </div>
                )
            }
        }
        // ReactDOM.render(虚拟dom,真实Dom)
        ReactDOM.render(<Login />, document.getElementById('test'))
</script>

2.非受控组件

  • 非受控组件 非受控组件将数据存储在 DOM 中,而不是组件内,这比较类似于传统的 HTML 表单元素。 非受控组件的值不受组件自身的 state props 控制 非受控组件使用refDOM 中获取元素数据
 <script type="text/babel">
        // 非受控组件
        class Login extends React.Component {
            btnSub = (e) => {
                e.preventDefault()
                console.log(e)
                let { username, password } = this
                alert(`你输入的用户名是${username.value},密码是${password.value}`)
            }
            render() {
                return (
                    <div>
                        <form action="https://kaifa.baidu.com/" onSubmit={this.btnSub}>
                            账号:<input type="text" ref={c => this.username = c} placeholder="输入数据" name='username' />
                            密码:<input type="text" ref={c => this.password = c} placeholder="输入密码" name='password' />
                            <button type="submit">点击登录</button>
                        </form>
                    </div>
                )
            }
        }
        // ReactDOM.render(虚拟dom,真实Dom)
        ReactDOM.render(<Login />, document.getElementById('test'))
</script>

3.使用组件建议

  1. 尽可能使用受控组件
  2. 受控组件是将状态交由 React 处理,可以是任何元素不局限于表单元素
  3. 对于有大量表单元素的页面,使用受控组件会使程序变得繁琐难控,此时使用非受控组件更为明智
  4. 在受控组件中,数据流是单向的( state 是变化来源),因此在改变state时都应该使用 setState ,而不要强制赋值
  5. Refs 不能用于函数式组件,因为函数式组件没有实例
  6. 在函数式组件内部,是可以使用Refs

二,React生命周期

  • 生命周期函数是指组件中在某个阶段会自动执行的函数。比如我们执行使用render函数,在prop或者state变化时,render函数自动执行,因此render也是React生命周期函数的一员
  • React生命周期可以分为三个阶段:组件挂载阶段组件更新阶段组件销毁卸载阶段
  • react在版本16.3前后存在两套生命周期16.3之前为旧版之后则是新版,虽有新旧之分,但主体上大同小异。

1.旧版生命周期

React 面向组件编程(下)_第1张图片


旧版生命周期的三个阶段

  • 初始化阶段: 由ReactDOM.render()触发—初次渲染
    1. constructor()
    2. componentWillMount()
    3. render()
    4. componentDidMount()
  • 更新阶段: 由组件内部this.setSate()或父组件重新render触发
    1. shouldComponentUpdate()
    2. componentWillUpdate()
    3. render()
    4. componentDidUpdate()
  • 卸载组件: 由ReactDOM.unmountComponentAtNode()触发
    1. componentWillUnmount()

 <script type="text/babel">
        class Count extends React.Component {
            state = {
                count: 0
            }
            add = () => {
                let { count } = this.state
                this.setState({
                    count: count + 1
                })
                console.log(count)
            }
            death = () => {
                // 卸载组件
                ReactDOM.unmountComponentAtNode(document.getElementById('test'));
            }
            force = () => {
                this.forceUpdate()//强制更新
            }
            // 数据更新    '阀门~'
            shouldComponentUpdate() {
                console.log("shouldComponentUpdate")
                return true;//这里必须要有返回值,其次返回值默认是true
            }
            // 组件将要更新的钩子
            componentWillUpdate() {
                console.log('componentWillUpdate')
            }
            // 组件更新完成的钩子
            componentDidUpdate() {
                console.log('componentDidMount')
            }
            render() {
                console.log('render')
                return (
                    <div>
                        <h1>当前求和为:{this.state.count}</h1>
                        <button onClick={this.add}>点我+1</button>
                        <button onClick={this.death}>卸载组件</button>
                        <button onClick={this.force}>不更改任何状态中的数据,强制更新</button>
                    </div>
                )
            }
        }
        //父组件
        class A extends React.Component {
            state = {
                carName: '红旗'
            }
            changeCar = () => {
                this.setState({
                    carName: '黑骑士'
                })
            }
            render() {
                console.log('我是A')
                return (
                    <div>
                        <div>我是A组件</div>
                        <button onClick={this.changeCar}>换车</button>
                        <B carName={this.state.carName} />
                    </div>
                )
            }
        }
        //子组件
        class B extends A {
            // 数据更新    '阀门~'
            shouldComponentUpdate() {
                console.log("shouldComponentUpdate")
                return true;//这里必须要有返回值,其次返回值默认是true
            }
            // 组件将要更新的钩子
            componentWillUpdate() {
                console.log('componentWillUpdate')
            }
            // 组件更新完成的钩子
            componentDidUpdate() {
                console.log('componentDidMount')
            }
            // 组件将要接受新的数据
            componentWillReceiveProps() {
                console.log('componentWillReceiveProps')
            }
            render() {
                return (
                    <div>
                        <div>我是B组件接收的车是:{this.props.carName}</div>
                    </div>
                )
            }
        }
        ReactDOM.render(<A />, document.getElementById('test'))
</script>

2.新版生命周期

React 面向组件编程(下)_第2张图片

新版生命周期执行的三个阶段

  • 初始化阶段: 由ReactDOM.render()触发—初次渲染
    1. constructor()
    2. getDerivedStateFromProps
    3. render()
    4. componentDidMount()
  • 更新阶段: 由组件内部this.setSate()或父组件重新render触发
    1. getDerivedStateFromProps
    2. shouldComponentUpdate()
    3. render()
    4. getSnapshotBeforeUpdate
    5. componentDidUpdate()
  • 卸载组件: 由ReactDOM.unmountComponentAtNode()触发
    1. componentWillUnmount()
 <script type="text/babel">
        class Count extends React.Component {
            state = {
                count: 0
            }
            add = () => {
                let { count } = this.state
                this.setState({
                    count: count + 1
                })
                console.log(count)
            }
            death = () => {
                // 卸载组件
                ReactDOM.unmountComponentAtNode(document.getElementById('test'));
            }
            force = () => {
                this.forceUpdate()//强制更新
            }
            // 数据更新    '阀门~'
            shouldComponentUpdate() {
                console.log("shouldComponentUpdate")
                return true;//这里必须要有返回值,其次返回值默认是true
            }
            // 组件将要更新的钩子
            componentWillUpdate() {
                console.log('componentWillUpdate')
            }
            // 组件更新完成的钩子
            componentDidUpdate() {
                console.log('componentDidMount')
            }
            render() {
                console.log('render')
                return (
                    <div>
                        <h1>当前求和为:{this.state.count}</h1>
                        <button onClick={this.add}>点我+1</button>
                        <button onClick={this.death}>卸载组件</button>
                        <button onClick={this.force}>不更改任何状态中的数据,强制更新</button>
                    </div>
                )
            }
        }
        class A extends React.Component {
            state = {
                carName: '红旗'
            }
            constructor(props){
                state
            }
            changeCar = () => {
                this.setState({
                    carName: '黑骑士'
                })
            }
            static getDerivedStateFromProps(props, state) {
                // 这里必须要一个返回值  ==> state or null
                // 这里的state会覆盖掉原本的状态并且后续也无法修改
                // 能将外部的接受的props复制给组件自身的state
                // 如果你希望自身的state 一直,全部,依赖于外部的props,那么可以使用这个生命周期函数
                return {
                    carName: '兰博基尼'
                }
            }
            // 获取数据更新前的快照,能拿到就的props和state
            getSnapshotBeforeUpdate(prevProp,prevState){
                
            }
            render() {
                console.log('我是A')
                return (
                    <div>
                        <div>我是A组件</div>
                        <button onClick={this.changeCar}>换车</button>
                        <B carName={this.state.carName} />
                    </div>
                )
            }
        }
        class B extends A {
            // 数据更新    '阀门~'
            shouldComponentUpdate() {
                console.log("shouldComponentUpdate")
                return true;//这里必须要有返回值,其次返回值默认是true
            }
            // 组件将要挂载
            UNSAFE_componentWillMount() {
                console.log('componentWillMount')
            }
            // 组件将要更新的钩子
            UNSAFE_componentWillUpdate() {
                console.log('componentWillUpdate')
            }
            // 组件更新完成的钩子
            componentDidUpdate() {
                console.log('componentDidMount')
            }
            // 组件将要接受新的数据
            UNSAFE_componentWillReceiveProps() {
                console.log('componentWillReceiveProps')
            }
            render() {
                return (
                    <div>
                        <div>我是B组件接收的车是:{this.props.carName}</div>
                    </div>
                )
            }
        }
        ReactDOM.render(<A />, document.getElementById('test'))

    </script>

新版与旧版生命周期的区别

  • 新生命周期中去掉了三个 will 钩子,分别为 componentWillMountcomponentWillReceivePropscomponentWillUpdate
  • 新生命周期中新增了两个钩子,分别为 getDerivedStateFromProps(从 props 中得到衍生的 state )和 getSnapshotBeforeUpdate

重要的勾子

  1. render:初始化渲染或更新渲染调用
  2. componentDidMount:开启监听, 发送ajax请求
  3. componentWillUnmount:做一些收尾工作, 如: 清理定时器

即将废弃的勾子

  1. componentWillMount
  2. componentWillReceiveProps
  3. componentWillUpdate
  4. 现在使用会出现警告,下一个大版本需要加上UNSAFE_前缀才能使用,以后可能会被彻底废弃,不建议使用。

三,高阶函数和函数柯里化的理解

1.高阶函数

  • JavaScript的函数其实都指向某个变量。既然变量可以指向函数,函数的参数能接收变量,那么一个函数就可以接收另一个函数作为参数,这种函数就称之为高阶函数。
  • 通俗一点就是:函数作为参数传入,这样的函数称为高阶函数,
  • 常见的高阶函数:Promise,setTimeout,arr.map(数组方法)

2.函数柯里化

  • 通过函数继续调用,返回值为函数的方式,实现多次接受参数,最后统一处理的函数编码形式
function sum(a){
    return (b)=>{
        return (c)=>{
            return a + b + c
        }
    }
}
const result = sum(1)(2)(3)

3.使用函数柯里化实例

class Login extends React.Component {
    // 初始化状态
    state = {
        username:'', // 用户名
        password:'', // 密码
    }
    // 保存表单数据到状态中
    saveFormDate=(dataType,event)=>{ // 标识当前标签
        this.setState({[dataType]:event.target.value})
    }
    // 表单提交的回调
    handleSubmit=(event)=>{
        event.preventDefault(); // 阻止默认事件
        
        let {username,password} = this.state
        alert(`你输入的用户名是${username},密码是${password}`)
    }
    render(){
        return(
            <div>
                <form action="https://www.baidu.com/" onSubmit={this.handleSubmit}>
                    用户名:<input type="text" onChange={(event)=>this.saveFormDate('username',event)} name="username" />    
                    密码:<input type="text" onChange={(event)=>this.saveFormDate('password',event)} name="password" />
                    <button type="submit">登录</button>  
                </form>
            </div>
        )
    }
}

4.不使用函数柯里化

class Login extends React.Component {
    // 初始化状态
    state = {
        username:'', // 用户名
        password:'', // 密码
    }
    // 保存表单数据到状态中
    saveFormDate=(dataType)=>{ // 标识当前标签
        return (event)=>{ // 这里的回调谁执行? input标签的 onChange事件
            this.setState({[dataType]:event.target.value})
        }
    }
    // 表单提交的回调
    handleSubmit=(event)=>{
        event.preventDefault(); // 阻止默认事件
        
        let {username,password} = this.state
        alert(`你输入的用户名是${username},密码是${password}`)
    }
    render(){
        return(
            <div>
                <form action="https://www.baidu.com/" onSubmit={this.handleSubmit}>
                    用户名:<input type="text" onChange={this.saveFormDate('username')} name="username" />    
                    密码:<input type="text" onChange={this.saveFormDate('password')} name="password" />
                    <button type="submit">登录</button>  
                </form>
            </div>
        )
    }
}


总结

以上就是React面向组件编程中剩下的一部分。希望本篇文章能够帮助到你,若有错误欢迎指出,不懂得可以评论区或者私信问我,我也会一 一解答。谢谢观看!
我的其他文章:https://blog.csdn.net/m0_60970928?type=blog

你可能感兴趣的:(react,react.js,javascript,前端)