每天对自己多问几个为什么,总是有着想象不到的收获。 一个菜鸟小白的成长之路(copyer)

​在react中 state 和 props是两个非常重要的属性,并且常用的属性。简单来说:都是用来保存数据状态的。

需注意的是state,props的每一次改动都会使页面重新渲染一次。

state的解释

state 意为 状态,组件内部的状态。

state是一个可变的属性,控制组件内部的状态

state 一般用于组件内部的状态维护,更新组建内部的数据,状态,更新子组件的props等

props的解释

PropsProperties的简写。

Props用于组件之间的通信,一种数据传递的方式。由于React的数据流是自上而下的,所以是从父组件向子组件进行传递。

props是只读属性。想要修改props,只能从父组件修改,然后传递给子组件。

props的形成

都知道, react 中的 jsx 会通过 babel转化成 createElement函数。所以,这里主要就是要知道createElement这个函数。话不多说,先看实例,然后看createElement的源码。

jsx转化成createElement的实例(babel官网的转化)

根据上面的转化和图解:

可以看,createElement 接受多个参数,

第一个参数为组件的名称(大写字母就是组件的名称,小写字母开头,就是原生的html标签),

第二个参数为props,如果没有props,就是为 null

第三个参数及跟多的参数(可选参数)

  • 如果没有子元素,就是undefined
  • 如果有子元素,那么子元素的createElement的函数就作为参数,如果有多个子元素,就依次排列下去(跟vue3的h函数有点区别,h函数的三个参数是数组,存放子元素的h函数)

看完了上面的分析,是不是对React.createElement函数有点认识了啊,那么接下来看看源码是怎么实现的吧。(这个函数不复杂,但是我还是省略一些代码,便于理解)

const RESERVED_PROPS = {    // 处理props, 排除特殊的关键字 key ref 等等key: true,ref: true,__self: true,__source: true,
};export function createElement(type, config, children) {let propName;const props = {};   //  定义一个props的空对象//... 省略代码// 遍历 config 赋值给 propsfor (propName in config) {  if (hasOwnProperty.call(config, propName) &&  // propsName在config中!RESERVED_PROPS.hasOwnProperty(propName)  // propsName不是关键词) {props[propName] = config[propName];}}}// 获取第二个参数后面的参数个数 const childrenLength = arguments.length - 2;if (childrenLength === 1) {   // 如果长度为1,就是一个ReactElementprops.children = children;} else if (childrenLength > 1) {  // 如果长度为1, 就是一个数组,保存着多个ReactElementconst childArray = Array(childrenLength);for (let i = 0; i < childrenLength; i++) {childArray[i] = arguments[i + 2];}// ...props.children = childArray;}return ReactElement( // 生成一个ReactElement的虚拟DOMtype,key,ref,self,source,ReactCurrentOwner.current,props,);
}

看望上面的代码,就可以很清楚的了解props的组成。

  • let props = {} props是一个对象
  • propName in config 循环createElement的第二个参数config,第二个参数,就是组件中写的props
  • props.children 就是组件中是否存在子元素。如果没有子元素,值就是undefined;如果是有一个子元素,值就是ReactElement元素;如果有多个,值就是一个数组,数组中存着ReactElement元素

props.children

上面的源码解析中已经中分析了,可以继续看上面的分析

defaultProps

在定义中组件的时候,我们可以给组件的props设置默认值,可以有效的防止没有传递对应的props,是程序报错

具体用法:

// 定义组件
const Test = (props) => {const { title } = propsreturn (<div>{title}</div>)
}
Test.defaultProps = {title: 'james'
}//使用组件
const App = () => {return (<div><Test title="kobe" />  </div>)
}

在上面使用Test组件的时候,如果传递了title,那么Test中,title就是kobe。如果没有传递title,那么组件中的title就是james

源码分析

createElement中的一个参数,就是组件的名称(type)

// 源码部分处理默认值
if (type && type.defaultProps) {const defaultProps = type.defaultProps;for (propName in defaultProps) {    // 循环默认props,对象if (props[propName] === undefined) {   // 如果在props中的值为undefined,使用默认值props[propName] = defaultProps[propName];}}}

displayName

displayName:就是组件取个名字,便于区分。

function Test() {}
Test.displayName = 'OwnTest'   // OwnTest用于展示

用途:

  • 在react的设置设计模式中的组合模式,就需要通过判断传递的子组件来进行渲染。
  • 调试工具的调试的名称显示

PropTypes

对组件的props的类型限定。如果JavaScript是个弱语言,会自动进行隐式转化,容易造成react的程序报错。所以,我们就需要对类型进行限定。

所以,prop-types 就很好对组件的类名进行限定。

安装:

npm install --save prop-types

官网地址:

https://zh-hans.reactjs.org/docs/typechecking-with-proptypes.html#gatsby-focus-wrapper

示例:

import PropTypes from 'prop-types';class Greeting extends React.Component {render() {return (<h1>Hello, {this.props.name}</h1>);}
}Greeting.propTypes = {name: PropTypes.string
};

类型限定:

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,// 一个 React 元素类型(即,MyComponent)。optionalElementType: PropTypes.elementType,// 你也可以声明 prop 为类的实例,这里使用// JS 的 instanceof 操作符。optionalMessage: PropTypes.instanceOf(Message),// 你可以让你的 prop 只能是特定的值,指定它为// 枚举类型。optionalEnum: PropTypes.oneOf(['News', 'Photos']),// 一个对象可以是几种类型中的任意一个类型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}),// An object with warnings on extra propertiesoptionalObjectWithStrictShape: PropTypes.exact({name: PropTypes.string,quantity: PropTypes.number}),// 你可以在任何 PropTypes 属性后面加上 `isRequired` ,确保// 这个 prop 没有被提供时,会打印警告信息。requiredFunc: PropTypes.func.isRequired,// 任意类型的必需数据requiredAny: PropTypes.any.isRequired,// 你可以指定一个自定义验证器。它在验证失败时应返回一个 Error 对象。// 请不要使用 `console.warn` 或抛出异常,因为这在 `oneOfType` 中不会起作用。customProp: function(props, propName, componentName) {if (!/matchme/.test(props[propName])) {return new Error('Invalid prop `' + propName + '` supplied to' +' `' + componentName + '`. Validation failed.');}},// 你也可以提供一个自定义的 `arrayOf` 或 `objectOf` 验证器。// 它应该在验证失败时返回一个 Error 对象。// 验证器将验证数组或对象中的每个值。验证器的前两个参数// 第一个是数组或对象本身// 第二个是他们当前的键。customArrayProp: PropTypes.arrayOf(function(propValue, key, componentName, location, propFullName) {if (!/matchme/.test(propValue[key])) {return new Error('Invalid prop `' + propFullName + '` supplied to' +' `' + componentName + '`. Validation failed.');}})
};

哈哈哈,上面的有点多,不用记太多,记住常用的就行了。如果有特殊的需求,就再去查官网吧。

TypeScript对props的限定

在上面,就是对props的类型限定和默认值的设置,在ts中就能完美的解决。

类组件

React.Component<P, S>

P: 就是对props的类型进行限定。

S:就是对state的类型限定

// node_modules/@types/react/index.d.tsclass Component<P, S> {//设置静态属性static contextType?: Context<any>;context: any;//限定props的类型,为readonly类型,只读的constructor(props: Readonly<P>);constructor(props: P, context?: any);setState<K extends keyof S>(state: ((prevState: Readonly<S>, props: Readonly<P>) => (Pick<S, K> | S | null)) | (Pick<S, K> | S | null),callback?: () => void): void;forceUpdate(callback?: () => void): void;//render的类型render(): ReactNode;//对props的类型限定readonly props: Readonly<P> & Readonly<{ children?: ReactNode }>;//state的类型限定state: Readonly<S>;refs: {[key: string]: ReactInstance};}

函数组件

React.FC<IProps>

IProps: 就是对props的类型进行限定

type FC<P = {}> = FunctionComponent<P>;interface FunctionComponent<P = {}> {//对props进行限定, 返回值是一个ReactElement对象,为了生成虚拟DOM(props: PropsWithChildren<P>, context?: any): ReactElement | null;propTypes?: WeakValidationMap<P>;contextTypes?: ValidationMap<any>;defaultProps?: Partial<P>;displayName?: string;
}

props的类型 :PropsWithChildren<P>

这里PropsWithChildren中内部实现了props新增children属性。

总结

​ 目前对props的所有认识,就在这里,以后遇到新的知识,然后在进行补充。如果上面的有错误,可以提出来哟。

附加信息:createElement的完整源码

/*** Create and return a new ReactElement of the given type.* See https://reactjs.org/docs/react-api.html#createelement*/
export function createElement(type, config, children) {let propName;// Reserved names are extractedconst props = {};let key = null;let ref = null;let self = null;let source = null;if (config != null) {if (hasValidRef(config)) {ref = config.ref;if (__DEV__) {warnIfStringRefCannotBeAutoConverted(config);}}if (hasValidKey(config)) {key = '' + config.key;}self = config.__self === undefined ? null : config.__self;source = config.__source === undefined ? null : config.__source;// Remaining properties are added to a new props objectfor (propName in config) {if (hasOwnProperty.call(config, propName) &&!RESERVED_PROPS.hasOwnProperty(propName)  // reserved_props) {props[propName] = config[propName];}}}// Children can be more than one argument, and those are transferred onto// the newly allocated props object.const childrenLength = arguments.length - 2;if (childrenLength === 1) {props.children = children;} else if (childrenLength > 1) {const childArray = Array(childrenLength);for (let i = 0; i < childrenLength; i++) {childArray[i] = arguments[i + 2];}if (__DEV__) {if (Object.freeze) {Object.freeze(childArray);}}props.children = childArray;}// Resolve default propsif (type && type.defaultProps) {const defaultProps = type.defaultProps;for (propName in defaultProps) {if (props[propName] === undefined) {props[propName] = defaultProps[propName];}}}if (__DEV__) {if (key || ref) {const displayName =typeof type === 'function'? type.displayName || type.name || 'Unknown': type;if (key) {defineKeyPropWarningGetter(props, displayName);}if (ref) {defineRefPropWarningGetter(props, displayName);}}}return ReactElement(type,key,ref,self,source,ReactCurrentOwner.current,props,);
}

彻底理解react中的props相关推荐

  1. [react] 为什么说React中的props是只读的?

    [react] 为什么说React中的props是只读的? React 组件都必须像纯函数一样保护它们的 props 不被更改. 将react组件理解成纯函数,数据流驱动,参数传入不允许做更改 扩展 ...

  2. [react] React中验证props的目的是什么?

    [react] React中验证props的目的是什么? 对属性进行强检验,避免运行时报错 我是歌谣,欢迎和大家一起交流前后端知识.放弃很容易, 但坚持一定很酷.欢迎大家一起讨论 主目录 与歌谣一起通 ...

  3. 如何理解react中的super(),super(props)

    用es6的class(类)的方法创建组件: 子类继承父类的属性:需要使用super()继续父类的属性,同时创建this(子类本身没有this); 如果像上图一样需要定义props的属性 this.pr ...

  4. 理解react中的高阶组件和高阶函数

    高阶组件 ES6中使用关键字class来使它的语法有和 类 相似的写法和功能,但是它的本质还是一个函数. 因此,高阶组件本质上是一个函数,只是这种组件(函数)接收一个组件,返回一个新的组件. 比如下面 ...

  5. React开发(164):React中this.props.children续集

  6. React开发(163):React中this.props.children

  7. react中的双向绑定

    前言:因为项目原因需要学习另一个超级火的框架react, 因为之前一直使用vue进行开发,所以在学习react中会不自觉的代入一些vue中的概念来理解react中的实现,下面就通过对比学习的方式记录下 ...

  8. react发送Ajax中文问号,在React中你真的用对了Ajax吗?

    通过AJAX加载初始数据 通过AJAX加载数据是一个很普遍的场景.在React组件中如何通过AJAX请求来加载数据呢?首先,AJAX请求的源URL应该通过props传入:其次,最好在component ...

  9. react 渲染道具_在React中学习分解道具的基础

    react 渲染道具 by Evelyn Chan 通过伊芙琳·陈 在React中学习分解道具的基础 (Learn the basics of destructuring props in React ...

最新文章

  1. 孙鑫VC++课程中用到的函数一览
  2. PHP基于数组的分页函数(核心函数array_slice())
  3. 一名新晋程序员的自述:我的编程自学之路
  4. Dos下命令运行带有包名的Java类
  5. 三级菜单 ajax 已经测试成功
  6. apache php 3秒,php版本(5.3,5.5,7.0)及运行模式(fast-cgi/fpm,apache模块)之间性能对比测试...
  7. 定义返回函数指针(地址)的函数
  8. 再学 GDI+[41]: 文本输出 - 控制输出字符的个数
  9. 雷电模拟器7抓包安装证书
  10. Google Arcore
  11. Radius 协议介绍
  12. python:Craps赌博游戏
  13. [Maven实战-许晓斌]-[第三章] Mave使用入门二(在IDE中的使用) [第四章] 案例的背景介绍...
  14. 用 LSTM 预测股票价格
  15. 饥荒如何解锁机器人_《饥荒》全部人物怎样解锁 全人物解锁条件及方法一览...
  16. VS1003调试例程
  17. 【游戏】LOL只能攻击英雄,点不了小兵解决办法
  18. Python小课们是如何赚钱的
  19. c 语言多个if并联使用,if的嵌套和多个并列if的效率有关问题
  20. Harray Potter and the Sorcerer's Stone

热门文章

  1. 抖音的数据抓取与数据背后的淘宝
  2. MFC更换背景(基于对话框)
  3. 资料结束符EOF,system(quot;stty rawquot;)
  4. 安科瑞远程预付费电能管理系统在上海星空广场项目的设计与应用-安科瑞薛炯毅
  5. 在Jetson Nano上安装numba
  6. 医疗器械之-输尿管软管镜
  7. qq 游戏计算机内存不足,腾讯手游助手显示内存不足的解决方法
  8. Android之JNI NDK错误找不到jni.h 小黄x Type xxx could not be resolved
  9. java Object数组
  10. 一篇文章带你搞懂进化树