前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >小结React(三):state、props、Refs

小结React(三):state、props、Refs

原创
作者头像
前端林子
修改于 2019-05-01 16:56:34
修改于 2019-05-01 16:56:34
7.6K00
代码可运行
举报
文章被收录于专栏:前端技术总结前端技术总结
运行总次数:0
代码可运行

0.引入

在React中state、props、Refs都是最基础的概念,本文将同时梳理下这三个知识点,主要内容包括:

1.state

React把每一个有状态的组件都看成是一个状态机,组件内部通过state来维护组件状态的变化。

在事件中触发setState()来修改state数据,state改变后会重新进行render()(React生命周期的内容,更多可点击

在需要对用户输入、服务器请求或者时间变化等做出响应时,使用state。

React目前支持的事件列表:

还有些不常用的事件这里没有具体列出,如有兴趣可查看

2.props

(1)React中的数据流是自上而下,从父组件流向子组件。

(2)子组件从父组件提供的props中获取数据,并进行渲染,一般是纯展示的组件。

(3)如果父组件的props更新,则该组件下面所有用到这个属性的子组件,都会重新进行render()(React生命周期的内容,更多可点击

(4)props是只读的,props是只读的,props是只读的。不要试图修改props,否则会报错。

(5)propTypes进行类型检查:

校验类型包括基本类型、对象、数组、枚举。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
import PropTypes from 'prop-types';

MyComponent.propTypes = {
    // 你可以将属性声明为 JS 原生类型,默认情况下
    // 这些属性都是可选的
    optionalArray: PropTypes.array,
    optionalBool: PropTypes.bool,
    optionalFunc: PropTypes.func,
    optionalNumber: PropTypes.number,
    optionalObject: PropTypes.object,
    optionalString: PropTypes.string,
    optionalSymbol: PropTypes.symbol,

    // 任何可被渲染的元素(包括数字、字符串、元素或数组)(或 Fragment) 也包含这些类型
    optionalNode: PropTypes.node,

    // 一个 React 元素
    optionalElement: PropTypes.element,

    // 你也可以声明 prop 为类的实例,这里使用JS 的 instanceof 操作符
    optionalMessage: PropTypes.instanceOf(Message),

    // 你可以让你的 prop 只能是特定的值,指定它为枚举类型
    optionalEnum: PropTypes.oneOf(['News', 'Photos']),
};

除此之外,还可以对数组、对象类型做些比较深入的校验,如指定一个对象由特定的类型值组成。如果还不能满足需求,还可以自定义验证规则。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
import PropTypes from 'prop-types';

MyComponent.propTypes = {
    // 一个对象可以是几种类型中的任意一个类型
    optionalUnion: PropTypes.oneOfType([
        PropTypes.string,
        PropTypes.number,
        PropTypes.instanceOf(Message)
    ]),

    // 可以指定一个数组由某一类型的元素组成
    optionalArrayOf: PropTypes.arrayOf(PropTypes.number),

    // 可以指定一个对象由某一类型的值组成
    optionalObjectOf: PropTypes.objectOf(PropTypes.number),

    // 可以指定一个对象由特定的类型值组成
    optionalObjectWithShape: PropTypes.shape({
        color: PropTypes.string,
        fontSize: PropTypes.number
    }),

    // 你可以指定一个自定义验证器。它在验证失败时应返回一个 Error 对象。
    // 请不要使用 `console.warn` 或抛出异常,因为这在 `onOfType` 中不会起作用。
    customProp: function (props, propName, componentName) {
        if (!/matchme/.test(props[propName])) {
            return new Error(
                'Invalid prop `' + propName + '` supplied to' +
                ' `' + componentName + '`. Validation failed.'
            );
        }
    },
};

如果某个属性是必须的,那么就在类型后面加上isRequired:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
import PropTypes from 'prop-types';

MyComponent.propTypes = {
    // 你可以在任何 PropTypes 属性后面加上 `isRequired` ,确保
    // 这个 prop 没有被提供时,会打印警告信息
    requiredFunc: PropTypes.func.isRequired,

    // 任意类型的数据
    requiredAny: PropTypes.any.isRequired,
};

下面是父组件给子组件传递数据的示例:

父组件设置:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<Greeting name="Peter" />

子组件读取:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
import React from 'react';
class Greeting extends React.Component {
    render() {
        return (
            <div>Hello,{this.props.name}</div>
        );
    }
}
export default Greeting;

上述就是父组件设置name属性,子组件通过this.props.name读取。那如果从父组件要传递个age属性给子组件,可以继续在父组件中设置age属性:

父组件设置:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<Greeting name="Peter" age="16"/>

子组件读取:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
import React from 'react';
class Greeting extends React.Component {
    render() {
        return (
            <div>Hello,{this.props.name},age is {this.props.age}</div>
        );
    }
}
export default Greeting;

那如果还要继续传递gender、address、hobby等属性,还需要继续在父组件中一个个添加吗?

是可以写,但代码会写的比较多:

父组件设置:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
const person = {
    name: "Peter",
    age: "16",
    gender: "male",
    address:"xxx",
    hobby: "coding"
}
...
<Greeting
    name={person.name}
    age={person.age}
    gender={person.gender}
    address={person.address}
    hobby={person.hobby}
/>

子组件获取:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
import React from 'react';
class Greeting extends React.Component{
  let {name,age,gender,address,hobby} = this.props;
  render(){
    return (
      <div>Hello,{name},age is {age}</div>
      <div>gender:{gender}</div>
      <div>address:{address}</div>
      <div>hobby:{hobby}</div>
    );
  }
}
export default Greeting;

实际上这里在父组件设置属性时,可以用...把属性一次性地传递给子组件。避免了上述写法中手动传递多个属性,导致代码要写得很长的情况。

父组件设置:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
const person = {
    name:"Peter",
    age:"16",
    gender:"male",
    address:"xxx",
    hobby: "coding"
}
...
<Greeting {...person} />

3.Refs

(1)可以用来访问在render()中的Dom节点

虽然也可以通过document.getElementById(“xxx”)来获取Dom节点,但React推荐不要直接操作Dom节点,只有用Refs才是访问组件内部Dom元素的唯一可靠方法。

(2)使用场景:

  • 控制input/video/audio,例如输入框聚焦、文本选择、媒体播放操作;
  • 触发命令式动画
  • 与第三方 DOM 库交互,比如 ECharts、地图 API

注意:不要滥用Refs。

(3)使用Refs的三种方式:

  • 字符串类型的Refs
  • 回调函数
  • React.createRef()

3.1字符串类型的Refs

这种方式是比较老的用法了,React已明确表示这种用法已经过时,并且可能会移除掉,建议用回调函数或者React.createRef()(React 16.3之后引入的)的方式来访问refs,不过还是简单看下它的用法。

它的用法是这样的:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
import React from 'react';
class Greeting extends React.Component {
    constructor(props) {
        super(props);
    }
    handleClick() {
        this.refs.inputTest.focus();
    }
    render() {
        return (
            <div>
                <input type="text" ref="inputTest" />
                <input
                    type="button"
                    value="点我输入框获取焦点"
                    onClick={this.handleClick.bind(this)}
                />
            </div>
        );
    }
}
export default Greeting;

3.2回调函数

上述代码用回调函数的方式来实现:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
import React from 'react';
class TextInput extends React.Component {
    constructor(props) {
        super(props);

        this.textInput = null;

        this.setTextInput = ele => {
            this.textInput = ele;
        }

        this.focusTextInput = () => {
            if (this.textInput) {
                this.textInput.focus();
            }
        }
    }

    render() {
        return (
            <div>
                <input type="text" ref={this.setTextInput} />
                <input
                    type="button"
                    value="点我输入框获取焦点"
                    onClick={this.focusTextInput}
                />
            </div>
        );
    }
}
export default TextInput;

ref传递的是一个函数:使用ref的回调函数,将text输入框的Dom节点存储到React。

3.3React.createRef()

如果是v16.3之后的React,那么可以使用这种方法。

创建Refs:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
this.myRef = React.createRef();

通过ref属性来获取React元素

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
return <div ref={this.myRef} />;

访问Refs:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
const node = this.myRef.current;

和回调函数传递一个函数不同,React.createRef()传递的是React.createRef()创建的ref属性。

上述代码用React.createRef()的方式来实现:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
import React from 'react';
class TextInput extends React.Component {
    constructor(props) {
        super(props);
        this.handleClick = this.handleClick.bind(this);
        // 通过React.createRef();来创建Refs
        this.textInput = React.createRef();
    }
    handleClick() {
        // 通过 this.textInput.current访问Dom节点
        this.textInput.current.focus();
    }
    render() {
        return (
            <div>
                <input type="text" ref={this.textInput} />
                <input
                    type="button"
                    value="点我输入框获取焦点"
                    onClick={this.handleClick}
                />
            </div>
        );
    }
}
export default TextInput;

注意:

(1)可以在类组件上使用ref属性

(2)不能在函数组件上使用ref属性,因为函数组件没有实例。如果想在函数组件上使用ref属性,那就需要转换为类组件。

(3)可以在函数组件内部可以使用ref属性,只要它指向一个 DOM 元素或者 class 组件。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// 1可以在类组件上使用ref属性
class CustomTextInput extends React.Component {
    // ...
}
class AutoFocusTextInput extends React.Component {
    constructor(props) {
        super(props);
        this.textInput = React.createRef();
    }

    componentDidMount() {
        this.textInput.current.focusTextInput();
    }

    render() {
        return (
            <CustomTextInput ref={this.textInput} />
        );
    }
}

// 2不能在函数组件上使用ref属性,因为函数组件没有实例
function MyFunctionComponent() {
    return <input />;
}

class Parent extends React.Component {
    constructor(props) {
        super(props);
        this.textInput = React.createRef();
    }
    render() {
        // This will *not* work!
        return (
            <MyFunctionComponent ref={this.textInput} />
        );
    }
}

// 3可以在函数组件内部使用ref属性
function CustomTextInput(props) {
    // textInput must be declared here so the ref can refer to it
    let textInput = React.createRef();

    function handleClick() {
        textInput.current.focus();
    }

    return (
        <div>
            <input
                type="text"
                ref={textInput} />

            <input
                type="button"
                value="Focus the text input"
                onClick={handleClick}
            />
        </div>
    );
}

createRef比回调函数看起来更加直观,不过也没有什么压倒性优势,只是希望提供一个更便捷的方法。

3.4React.forwardRef

React 16.3还提供了一个名为React.forwardRef的API,主要是用于贯穿过父元素直接获取子元素的ref。这里的应用场景涉及HOC使用ref的问题,具体内容会在总结HOC相关内容时介绍。

4.小结

最后再概况下state、props和refs:

state:把一个有状态的组件看成是一个状态机,组件内部通过state来维护组件状态的变化。

在DOM上注册事件,触发事件时通过setState()修改了state的数据,这会导致重新render()来更新虚拟DOM,虚拟DOM再转为DOM。

props:React中的数据流就像水流一样,自上而下,从父组件流向子组件。如同下图这个水竹一样的感觉,自上而下、层层传递地流淌。

Refs:获取render()中的DOM节点。

本文主要总结了React中state、props、refs的基础知识点,如有问题,欢迎指正。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
暂无评论
推荐阅读
(很全面)SpringBoot 集成 Apollo 配置中心
. 六、Kubernetes 的 SpringBoot 应用使用 Apollo 配置中心
JAVA葵花宝典
2020/03/31
18.4K0
(很全面)SpringBoot 集成 Apollo 配置中心
告别Eureka!Nacos也落伍了!这款配置中心才是新宠!
在我们微服务种,配置中心的选择有多种多样。小二哥之前使用Eureka、Nacos、Zookeeper这几种方案。
程序视点
2025/01/17
2240
告别Eureka!Nacos也落伍了!这款配置中心才是新宠!
新手也能轻松上手!Apollo配置中心搭建+配置+测试全攻略!0到1详解!
在头条文章里,我们把Apollo的基础知识分享了。这里我们一起动手实践下!这套文章实践下来,你也就可以掌握 Apollo 的应用和实践啦~ Apollo 配置中心创建项目与配置
程序视点
2025/01/17
9980
新手也能轻松上手!Apollo配置中心搭建+配置+测试全攻略!0到1详解!
Apollo配置中心使用篇
如果对配置中心完全没有过了解的,可以先移步去了解一下常用的开源配置中心组件,如: SpringCloud Config和Nacos等。
大忽悠爱学习
2023/04/18
9.9K0
Apollo配置中心使用篇
快速学习-Apollo从入门到精通
Apollo (阿波罗)是携程框架部门研发的分布式配置中心,能够集中化管理应用不同环境、不同集群的配置,配置修改后能够实时推送到应用端,并且具备规范的权限、流程治理等特性,适用于微服务配置管理场景。
cwl_java
2020/08/04
1.6K0
快速学习-Apollo从入门到精通
云计算运维kubernetes集群里集成Apollo配置中心
Apollo(阿波罗)是携程框架部门研发的分布式配置中心,能够集中化管理应用不同环境、不同集群的配置,配置修改后能够实时推送到应用端,并且具备规范的权限、流程治理等特性,适用于微服务配置管理场景。
王先森sec
2023/04/24
1.4K0
云计算运维kubernetes集群里集成Apollo配置中心
分布式配置中心之Apollo简易环境部署
Apollo(阿波罗)是携程框架部门研发的分布式配置中心,能够集中化管理应用不同环境、不同集群的配置,配置修改后能够实时推送到应用端,并且具备规范的权限、流程治理等特性,适用于微服务配置管理场景。 github地址为: https://github.com/ctripcorp/apollo 该项目提供了两种部署方式:本地部署和分布式部署。生产环境建议使用“分布式部署”。 因最近项目有使用配置中心的需求,在综合分析了apollo、Qconf、SpringCloud Config等一系列分布式配置中心后,初步选定apollo。 官方提供的分布式部署架构适合大规模集群环境。在其总体架构基础上做了精简,力求先跑起来,给开发部门提供环境,测试。
lyb-geek
2018/07/26
1.5K0
分布式配置中心之Apollo简易环境部署
快速学习-Apollo配置中心搭建
Apollo (阿波罗)是携程框架部门研发的分布式配置中心,能够集中化管理应用不同环境、不同集群的配置,配置修改后能够实时推送到应用端,并且具备规范的权限、流程治理等特性,适用于微服务配置管理场景。
cwl_java
2020/07/16
3.4K0
Apollo - 企业级配置中心的快速部署
下载页:https://github.com/ctripcorp/apollo/releases
十毛
2019/03/27
1.5K0
Apollo - 企业级配置中心的快速部署
Apollo 配置中心的部署与使用经验
准备好 compose.yml 及 。/initsql/初始化脚本,修改其中的 IP
易墨
2023/11/01
2.9K0
Apollo 配置中心的部署与使用经验
容器化生产环境集成apollo配置中心与skywalking全链路追踪
3.制作apollo-skywalking-docker-image镜像注意sk-plugin选择
千里行走
2019/11/08
2.3K0
SpringBoot+Mybatis+Mycat+Apollo
1.够集中化管理应用不同环境、不同集群的配置,配置修改后能够实时推送到应用端。
黑洞代码
2021/01/14
1.3K0
SpringBoot+Mybatis+Mycat+Apollo
在CentOS8下分布式部署Apollo配置中心
众所周知Apollo是携程开源的配置中心,所以中文文档也比较完善,因此这里就不过多赘述细节了。本文的主要目的是记录下如何在CentOS8下分布式部署Apollo配置中心。Apollo的功能亮点:
端碗吹水
2020/11/12
1.7K0
在CentOS8下分布式部署Apollo配置中心
CentOS 7 搭建基于携程Apollo(阿波罗)配置中心单机模式
Apollo(阿波罗)是携程框架部门研发的配置管理平台,能够集中化管理应用不同环境、不同集群的配置,配置修改后能够实时推送到应用端,并且具备规范的权限、流程治理等特性。服务端基于Spring Boot和Spring Cloud开发,打包后可以直接运行,不需要额外安装Tomcat等应用容器。Java客户端不依赖任何框架,能够运行于所有Java运行时环境,同时对Spring环境也有较好的支持。.Net客户端不依赖任何框架,能够运行于所有.Net运行时环境,而且已经支持.NET Core。 官网:https://
张善友
2018/03/28
4.7K0
CentOS 7 搭建基于携程Apollo(阿波罗)配置中心单机模式
干货 | 携程开源配置中心Apollo的设计与实现
作者简介 宋顺,携程框架研发部技术专家。2016年初加入携程,主要负责中间件产品的相关研发工作。毕业于复旦大学软件工程系,曾就职于大众点评,担任后台系统技术负责人。 1、What is Apollo 1.1 背景 随着程序功能的日益复杂,程序的配置日益增多:各种功能的开关、参数的配置、服务器的地址…… 对程序配置的期望值也越来越高:配置修改后实时生效,灰度发布,分环境、分集群管理配置,完善的权限、审核机制…… 在这样的大环境下,传统的通过配置文件、数据库等方式已经越来越无法满足开发人员对配置管理的需求。 A
携程技术
2018/03/16
3.4K0
干货 | 携程开源配置中心Apollo的设计与实现
apollo部署
本文档介绍了如何按照分布式部署的方式编译、打包、部署Apollo配置中心,从而可以在开发、测试、生产等环境分别部署运行。
章工运维
2023/05/19
2.2K0
微服务中集成分布式配置中心 Apollo
随着业务的发展、微服务架构的升级,服务的数量、程序的配置日益增多(各种微服务、各种服务器地址、各种参数),传统的配置文件方式和数据库的方式已无法满足开发人员对配置管理的要求:配置修改后实时生效,灰度发布,分环境、分集群管理配置,完善的权限、审核机制。分布式环境下,这些配置更加复杂。
aoho求索
2019/06/02
8880
芋道 Apollo 极简入门
本小节,参考《Apollo 部署文档 —— 分布式部署指南》和《Apollo 部署文档 —— Quick Start》文章,我们来单机部署一个 Apollo 服务。如下图所示:
芋道源码
2020/05/16
1.4K0
Apollo配置中心管理后台的详解
上篇【Apollo配置中心源码编译及搭建】搭建了Apollo。这篇来看看怎么使用Apollo管理后台。
BUG弄潮儿
2020/08/11
2.5K0
Apollo配置中心管理后台的详解
分布式配置中心之Apollo实战
微服务架构下,服务的数量视项目的规模大小而定,但数量肯定最少有十几二十个,这些微服务有时候共用一些配置,修改一个配置,这诸多服务都要跟着一起改。任务繁多,而且容易出错。
行百里er
2021/07/14
1.6K0
推荐阅读
相关推荐
(很全面)SpringBoot 集成 Apollo 配置中心
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档