React 面向组件编程(下)

这篇具有很好参考价值的文章主要介绍了React 面向组件编程(下)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

前言:

在React面向组件编程中,除了上一章节的组件实例的三大核心属性以外,还有很多重要的内容比如:React 的生命周期,受控组件与非受控组件,高阶函数和函数柯里化的理解等,在本文中会给大家继续讲解React 面向组件编程中剩余的内容。


一、受控组件与非受控组件

表单的组件分类:

  1. 受控组件
  2. 非受控组件

多数情况下,推荐使用受控组件实现表单。在受控组件中,表单数据由组件控制。
另外一种是非受控组件,这种方式下表单组件由DOM自身控制。


1. 受控组件

  1. 受控组件通过 props 获取其当前值,并通过回调函数(比如 onChange )通知变化
  2. 表单状态发生变化时,都会通知 React,将状态交给 React 进行处理,比如可以使用 useState 存储
  3. 受控组件中,组件渲染出的状态与它的 valuechecked 属性相对应
  4. 受控组件会更新 state 的流程
class Login extends React.Component {
    // 初始化状态
    state = {
        username:'', // 用户名
        password:'', // 密码
    }
    // 保存用户名到状态中
    saveUsername=(event)=>{
        this.setState({username:event.target.value})
    }
    // 保存密码到状态中
    savePassword=(event)=>{
        this.setState({password: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.saveUsername} name="username" />    
                    密码:<input type="text" onChange={this.savePassword} name="password" />
                    <button type="submit">登录</button>  
                </form>
            </div>
        )
    }
}

2. 非受控组件

非受控组件将数据存储在 DOM 中,而不是组件内,这比较类似于传统的 HTML 表单元素。

  1. 非受控组件的值不受组件自身的 stateprops 控制
  2. 非受控组件使用 refDOM 中获取元素数据
class Login extends React.Component {
    handleSubmit=(event)=>{
        // console.log(e>=event)
        event.preventDefault(); // 阻止默认事件
        
        let {username,password} = this
        alert(`你输入的用户名是${username.value},密码是${password.value}`)
    }
    render(){
        return(
            <div>
                <form action="https://www.baidu.com/" onSubmit={this.handleSubmit}>
                    用户名:<input type="text" ref={c=>this.username = c} name="username" />    
                    密码:<input type="text" ref={c=>this.password = c} name="password" />
                    <button type="submit">登录</button>  
                </form>
            </div>
        )
    }
}

3. 效果展示

React 面向组件编程(下),React,react.js,javascript,前端


4. 总结:

  1. React 中的组件分为受控组件和非受控组件
  2. 受控组件的两个要点:
    • 组件的 value 属性与 React 中的状态绑定
    • 组件内声明了 onChange 事件处理 value 的变化
  3. 非受控组件更像是传统的 HTML 表单元素,数据存储在 DOM 中,而不是组件内部,获取数据的方式是通过 ref 引用
  4. 一些建议:
    • 尽可能使用受控组件
    • 受控组件是将状态交由 React 处理,可以是任何元素,不局限于表单元素
    • 对于有大量表单元素的页面,使用受控组件会使程序变得繁琐难控,此时使用非受控组件更为明智
    • 在受控组件中,数据流是单向的( state 是变化来源),因此在改变 state 时都应该使用 setState ,而不要强制赋值
    • Refs 不能用于函数式组件,因为函数式组件没有实例
    • 在函数式组件内部,是可以使用 Refs

二、组件的生命周期

所谓的React生命周期,就是指组件从被创建出来,到被使用,最后被销毁的这么一个过程;
而在这个过程中,React提供了我们会自动执行的不同的钩子函数,我们称之为生命周期函数;

组件的生命周期大致分为三个阶段:组件挂载阶段,组件更新阶段,组件销毁卸载阶段

react在版本16.3前后存在两套生命周期,16.3之前为旧版,之后则是新版,虽有新旧之分,但主体上大同小异。


1. 对生命周期的理解

  1. 组件从创建到死亡它会经历一些特定的阶段。
  2. React组件中包含一系列勾子函数(生命周期回调函数), 会在特定的时刻调用。
  3. 我们在定义组件时,会在特定的生命周期回调函数中,做特定的工作。

2. 生命周期的三个阶段(旧)

React 面向组件编程(下),React,react.js,javascript,前端

  1. 初始化阶段: 由ReactDOM.render()触发—初次渲染
    1. constructor()
    2. componentWillMount()
    3. render()
    4. componentDidMount()
  2. 更新阶段: 由组件内部this.setSate()或父组件重新render触发
    1. shouldComponentUpdate()
    2. componentWillUpdate()
    3. render()
    4. componentDidUpdate()
  3. 卸载组件: 由ReactDOM.unmountComponentAtNode()触发
    1. componentWillUnmount()
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>生命周期旧</title>
</head>
<body>
    <!-- 准备好一个容器 -->
    <div id="test"></div>
    <!-- 引入 React 核心库 -->
    <script src="../js/react.development.js"></script>
    <!-- 引入 react-dom 用于支持 react 操作 DOM -->
    <script src="../js/react-dom.development.js"></script>

    <!-- 引入babel:
            1. ES6 ==> ES5
            2. jsx ==> js
    -->
    <script src="../js/babel.min.js"></script>

    <script type="text/babel">
        class Count extends React.Component {
            state = {
                count:0
            }
            add = ()=>{
                // 获取原状态
                let {count} = this.state
                // 更新状态
                this.setState({count:count+1})
            }
            death = ()=>{
                ReactDOM.unmountComponentAtNode(document.getElementById('test'))
            }
            force = ()=>{
                this.forceUpdate() // 强制更新
            }
            // 数据更新的 ‘阀门~’
            shouldComponentUpdate() { 
                console.log("Count --- shouldComponentUpdate");
                return true // 这里必须有返回4值,其次返回值默认是true
            }
            // 组件将要更新的钩子
            componentWillUpdate() {
                console.log("Count ---- componentWillUpdate");
            }
            // 组件更新完成的钩子
            componentDidUpdate() { 
                console.log("Count ---- componentDidUpdate");
            } 
            render(){
                console.log("render");
                let {count} = this.state
                return(
                    <div>
                        <h2>当前求和为:{count}</h2>
                        <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 ---- render');
                return(
                    <div>
                        <div>我是A组件</div>
                        <button onClick={this.changeCar}>换车</button>
                        <B carName={this.state.carName}></B>
                    </div>
                )
            }
        }
        // 子组件
        class B extends A {
            // 组件将要接收新的props的钩子
            componentWillReceiveProps(){
                console.log('B ---- componentWillReceiveProps');
            }
            // 数据更新的 ‘阀门~’
            shouldComponentUpdate() { 
                console.log("B --- shouldComponentUpdate");
                return true // 这里必须有返回4值,其次返回值默认是true
            }
            // 组件将要更新的钩子
            componentWillUpdate() {
                console.log("B ---- componentWillUpdate");
            }
            // 组件更新完成的钩子
            componentDidUpdate() { 
                console.log("B ---- componentDidUpdate");
            } 
            render(){
                console.log('B ---- render');
                return(
                    <div>
                        我是B组件,接收到的车是:{this.props.carName}
                    </div>
                )
            }
        }

        ReactDOM.render(<A />,document.getElementById('test'))
    </script>
</body>
</html>

3. 生命周期的三个阶段(新)

React 面向组件编程(下),React,react.js,javascript,前端

  1. 初始化阶段: 由ReactDOM.render()触发—初次渲染
    1. constructor()
    2. getDerivedStateFromProps
    3. render()
    4. componentDidMount()
  2. 更新阶段: 由组件内部this.setSate()或父组件重新render触发
    1. getDerivedStateFromProps
    2. shouldComponentUpdate()
    3. render()
    4. getSnapshotBeforeUpdate
    5. componentDidUpdate()
  3. 卸载组件: 由ReactDOM.unmountComponentAtNode()触发
    1. componentWillUnmount()
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>生命周期新</title>
</head>
<body>
    <!-- 准备好一个容器 -->
    <div id="test"></div>
    <!-- 引入 React 核心库 -->
    <script src="../js/17.0.1/react.development.js"></script>
    <!-- 引入 react-dom 用于支持 react 操作 DOM -->
    <script src="../js/17.0.1/react-dom.development.js"></script>
    <!-- 引入babel:1. ES6 ==> ES52. jsx ==> js -->
    <script src="../js/17.0.1/babel.min.js"></script>
    <script type="text/babel">
        class Count extends React.Component {
            state = {
                count:0
            }
            add = ()=>{
                // 获取原状态
                let {count} = this.state
                // 更新状态
                this.setState({count:count+1})
            }
            death = ()=>{
                ReactDOM.unmountComponentAtNode(document.getElementById('test'))
            }
            force = ()=>{
                this.forceUpdate() // 强制更新
            }
            // 数据更新的 ‘阀门~’
            shouldComponentUpdate() { 
                console.log("Count --- shouldComponentUpdate");
                return true // 这里必须有返回4值,其次返回值默认是true
            }
            // 组件将要更新的钩子
            componentWillUpdate() {
                console.log("Count ---- componentWillUpdate");
            }
            // 组件更新完成的钩子
            componentDidUpdate() { 
                console.log("Count ---- componentDidUpdate");
            } 
            render(){
                console.log("render");
                let {count} = this.state
                return(
                    <div>
                        <h2>当前求和为:{count}</h2>
                        <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:"QQ"}
            }
            // 获取护具更新前的快照,能拿到旧的props和state
            // 必须有返回值
            getSnapshotBeforeUpdate = (prevProps, prevState) => {

            }
            render(){
                console.log('A ---- render');
                return(
                    <div>
                        <div>我是A组件</div>
                        <button onClick={this.changeCar}>换车</button>
                        <B carName={this.state.carName}></B>
                    </div>
                )
            }
        }
        // 子组件
        class B extends A {
            // 组件将要接收新的props的钩子
            UNSAFE_componentWillReceiveProps(){
                console.log('B ---- componentWillReceiveProps');
            }
            // 数据更新的 ‘阀门~’
            shouldComponentUpdate() { 
                console.log("B --- shouldComponentUpdate");
                return true // 这里必须有返回4值,其次返回值默认是true
            }
            // 将要挂载时
            UNSAFE_componentWillMount() {
                console.log("Count --- componentWillUnMount");
            }
            // 组件将要更新的钩子
            UNSAFE_componentWillUpdate() {
                console.log("B ---- componentWillUpdate");
            }
            // 组件更新完成的钩子
            componentDidUpdate() { 
                console.log("B ---- componentDidUpdate");
            } 
            render(){
                console.log('B ---- render');
                return(
                    <div>
                        我是B组件,接收到的车是:{this.props.carName}
                    </div>
                )
            }
        }

        ReactDOM.render(<A />,document.getElementById('test'))
    </script>
</body>
</html>

4. 新旧生命周期的区别

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

5. 重要的勾子

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

6. 即将废弃的勾子

  1. componentWillMount
  2. componentWillReceiveProps
  3. componentWillUpdate

警告:

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


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

1. 高阶函数

如果一个函数符合下面2个规范中的任何一个,那么它就属于一个高阶函数

  1. 若A函数,接收的参数是一个函数,那么A就可以称为高阶函数
  2. 若A函数,它的返回值依然是一个函数,那么A就可以称为高阶函数

常见的高阶函数:Promise,setTimeout,arr.map(数组方法)


2. 函数的柯里化

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

function sum(a){
    return (b)=>{
        return (c)=>{
            return a + b + c
        }
    }
}
const result = sum(1)(2)(3)
console.log(result);

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

总结:

欢迎大家加入我的社区,在社区中会不定时发布一些精选内容:https://bbs.csdn.net/forums/db95ba6b828b43ababd4ee5e41e8d251?category=10003


以上就是 React 面向组件编程(下),不懂得也可以在评论区里问我或私聊我询问,以后会持续发布一些新的功能,敬请关注。
我的其他文章:https://blog.csdn.net/weixin_62897746?type=blog文章来源地址https://www.toymoban.com/news/detail-785063.html

到了这里,关于React 面向组件编程(下)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • JavaScript 框架比较:Angular、React、Vue.js

    在 Web 开发领域,JavaScript 提供大量技术栈可供选择。其中最典型的三套组合,分别是 MERN、MEAN 和 MEVN。这些首字母相同的选项各自代表不同的技术加工具组合。为了在这些技术栈中做出明智选择,让我们先从核心组件聊起,再对各自前端框架(React、Angular 和 Vue)进行简化比

    2024年01月20日
    浏览(59)
  • 前端react入门day03-react获取dom与组件通信

    (创作不易,感谢有你,你的支持,就是我前行的最大动力,如果看完对你有帮助,请留下您的足迹) 目录 受控表单绑定  React中获取DOM 组件通信 父传子  父传子-基础实现 父传子-props说明 父传子 - 特殊的prop children 子传父  使用状态提升实现兄弟组件通信 使用Context机制跨

    2024年02月01日
    浏览(55)
  • 前端react入门day02-React中的事件绑定与组件

    (创作不易,感谢有你,你的支持,就是我前行的最大动力,如果看完对你有帮助,请留下您的足迹) 目录 React中的事件绑定 React 基础事件绑定 使用事件对象参数  传递自定义参数  同时传递事件对象和自定义参数  React中的组件  组件是什么 React组件 useState  修改状态的规

    2024年02月06日
    浏览(86)
  • 从javascript到vue再到react:前端开发框架的演变

    目录 JavaScript: 动态语言的基础 JavaScript:Web开发的起点 Vue.js: 渐进式框架的兴起 Vue.js:简洁、高效的前端框架 React.js: 声明式UI的革新 React.js:强大、灵活的前端框架 演变之路与未来展望 演变过程 当提到前端开发中的框架时,JavaScript、Vue.js和React.js是三个最常见的名词。它

    2024年02月07日
    浏览(53)
  • 前端开发笔记 | React Hooks子组件和父组件交互

    前端开发框架目前比较常用的就是react、vue等,其中使用React Hooks 带来了不少的好处,今天来聊聊React Hooks开发方式下,子组件和父组件的交互。 子组件定义 父组件调用子组件 父组件定义 子组件中刷新父组件按钮文案 实际效果:点击子组件中“改变父组件按钮”,父组件中

    2024年02月11日
    浏览(83)
  • 【前端知识】React 基础巩固(十七)——组件化开发(一)

    什么是组件化开发? 分而治之的思想 将一个页面拆分成一个个小的功能块 将应用抽象成一颗组件树 React的组件相对于Vue更加的灵活和多样 按照不同的方式可以分为很多类组件 根据 组件的定义方式 ,分为: 函数组件 、 类组件 根据 组件内部是否有状态需要维护 ,分为:

    2024年02月12日
    浏览(69)
  • 【前端知识】React 基础巩固(十九)——组件化开发(三)

    Main.jsx TabControl/index.jsx TabControl/style.css

    2024年02月13日
    浏览(55)
  • 前端(十五)——开源一个用react封装的图片预览组件

    👵博主:小猫娃来啦 👵文章核心:开源一个react封装的图片预览组件 Gitee:点此跳转下载 CSDN:点此跳转下载 装依赖 运行 打开 创建一个React函数组件并命名为 ImageGallery 。 在组件内部,使用useState钩子来定义状态变量,并初始化为合适的初始值。 selectedImageUrl 来追踪当前选

    2024年02月10日
    浏览(56)
  • JavaScript框架 Angular、React、Vue.js 的全栈解决方案比较

    在 Web 开发领域,JavaScript 提供大量技术栈可供选择。其中最典型的三套组合,分别是 MERN、MEAN 和 MEVN。前端框架(React、Angular 和 Vue)进行简化比较。 MERN 技术栈包含四大具体组件: MongoDB:一款强大的 NoSQL 数据库,以灵活的 JSON 格式存储数据。 Express.js:一套极简但强大的

    2024年02月03日
    浏览(58)
  • Three.js 的组件库react-three-fiber和react-three-drei

    类似于这种字体,可以用Text或者Text3d,但是要处理一个问题,就是要保证字体一直正面视角。 这中间的处理比较的麻烦,于是可以使用react-three-drei中的Html来做这件事

    2024年01月24日
    浏览(63)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包