赞
踩
react 中通过 props 和 state 实现组件间的通信,对数据进行传递、操作。
在组件中可以通过 props 传递数据。
正常情况下,props是外部传入的,组件内部也可以通过一些方式来设置属性的默认值,属性不能被组件自己更改,但是你可以通过父组件主动重新渲染的方式来传入新的 props。
通俗来讲,就是在使用一个组件的时候,可以把参数放在标签的属性当中,所有的属性都会作为组件 props
对象的键值。通过箭头函数创建的组件,需要通过函数的参数来接收props
。
来看一个使用 props 传参的例子:
import React from 'react';
import ReactDOM from 'react-dom';
//函数组件
function Box(props) {
return <h1>Hello {props.name}!</h1>;
}
const element = <Box name="React"/>;
ReactDOM.render(
element,
document.getElementById('root')
);
在类组件中,可以通过组件类的 defaultProps 属性为 props 设置默认值。在父组件没有指定其值时,会使用这个默认值。propTypes 类型检查发生在 defaultProps 赋值后,所以类型检查也适用于 defaultProps。
import React from 'react'; import ReactDOM from 'react-dom'; class Box extends React.Component { //方式一:在类的内部设置静态属性 static defaultProps={ name:'react' } render() { return ( <h1>Hello, {this.props.name},age:{this.props.age}</h1> ); } } //方式二:在类的外面 设置defaultProps属性 Box.defaultProps = { age: 18 }; ReactDOM.render( <Box/>, document.getElementById('root') );
每个组件都可以获取到 props.children。它包含组件的开始标签和结束标签之间的内容。类似vue中的插槽。
看下面这个例子:
import React, { Component } from 'react'; import ReactDOM from 'react-dom'; class Content extends Component { render() { return ( <div>{this.props.children}</div> ); } } class Title extends Component { render() { return ( <div>欢迎进入{this.props.children} </div> ); } } ReactDOM.render( <Content> <Title>React</Title> <p>这里是内容</p> </Content>, document.getElementById('root') );
上面的代码中,在页面中渲染Content 的 props.children,最终会渲染出<Content></Content>标签中的所有内容,渲染页面的结果如下:
Props 验证使用 propTypes,它可以保证我们的应用组件被正确使用,React.PropTypes 提供很多验证器 (validator) 来验证传入数据是否有效。当向 props 传入无效数据时,JavaScript 控制台会抛出警告。
React.PropTypes 在 React v15.5 版本后已经移到了prop-types 库。
在终端中执行下面的命令,安装 prop-types 插件
yarn add prop-types -S
使用:
类名.propTypes={}
,来定义属性规则,固定写法,注意大小写。import React, { Component } from 'react'; import ReactDOM from 'react-dom'; import Proptypes from 'prop-types'; class Box extends Component { render() { return ( <div> 姓名: {this.props.name},年龄:{this.props.age} </div> ); } } Box.propTypes={ name:Proptypes.string.isRequired, //表示name为字符串类型,isRequired 必须要传 age:function(props,propName){ //自定义验证 if(props[propName]<20){ return new Error( 'Invalid prop `' + propName + '` Because it Less than 20.' ) } } } ReactDOM.render( <Box name="xiaoming" age={18} />, document.getElementById('root') );
prop-types 的验证规则:
规则 | 说明 |
---|---|
.array | 输入的类型为数组 |
.bool | 输入的类型为布尔 |
.func | 输入的类型为函数 |
.number | 输入的类型为数值 |
.object | 输入的类型为对象 |
.string | 输入的类型为字符串 |
.symbol | 输入的类型为symbol类型 |
以上为 js 的原生类型
规则 | 说明 |
---|---|
.node | 表示任何可被渲染的元素(包括数字、字符串、元素或数组) (或 Fragment) 也包含这些类型。 |
.element | 表示一个 React 元素,确保传递给组件的 children 中只包含一个元素。 |
.elementType | 表示一个 React 元素类型,即上面案例中的 Box |
.instanceOf() | 声明 prop 为是否为类的实例,这里使用 JS 的 instanceof 操作符 |
.oneOf() | 指定 prop 只能是特定的值,指定它为枚举类型 |
.oneOfType() | 一个对象可以是几种类型中的任意一个类型 |
.arrayOf() | 指定一个数组由某一类型的元素组成,例如只能由数字组成的数组 .arrayOf(PropTypes.number) |
.objectOf() | 指定一个对象由某一类型的值组成,使用方法同 .arrayOf() |
.shape() | 指定一个对象由特定的类型值组成 |
.isRequired | 在任何 PropTypes 属性后面加上 isRequired ,确保这个 prop 没有被提供时,会打印警告信息 |
部分语法使用如下:
import PropTypes from 'prop-types'; Box.propTypes = { // 你可以让你的 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 properties optionalObjectWithStrictShape: PropTypes.exact({ name: PropTypes.string, quantity: PropTypes.number }),
state 与 props 类似,但是 state 是私有的,并且完全受控于当前组件。
可以在类的构造函数中初始化状态 state,也可以在类中直接定义属性(下面2.1中的写法)来初始化状态 state 。通过 this.state 获取 state 中的数据内容。
import React, { Component } from 'react'; import ReactDOM from 'react-dom'; class Box extends Component { constructor() { super(); this.state = { name: 'xiaoming', age: 18 } } render() { return ( <div> 姓名: {this.state.name},年龄:{this.state.age} </div> ); } } ReactDOM.render( <Box />, document.getElementById('root') );
修改 state 中的数据内容,有以下三种方式:
import React, { Component } from 'react'; import ReactDOM from 'react-dom'; class Box extends Component { state={ name:"xiaoming" } componentDidMount(){ //第一种修改方式 this.setState({name:'zhangsan'}); //第二种修改方式 this.state.name="sssss"; this.setState({}); //第三种修改方式 this.setState((preState,props)=>{ return{ name:preState.name+'ccc' } },()=>{ //数据修改完成后的回调函数 }) } render() { return ( <div>姓名: {this.state.name}</div> ); } } ReactDOM.render( <Box />, document.getElementById('root') );
当使用第二种方式的时候,虽然修改后的数据也在浏览器端渲染出来了,但是在控制台中会输出下面的警告信息,所以不建议直接使用 this.state 修改数据。
react 和 vue 中对 state 中数据的修改都是异步的,在vue中可以使用$nextTick() 方法,获取修改后的数据内容,在 react 中通过使用上面的第三种方法,获取修改后的数据内容。
setState 对数据的更新,会做 merge 合并的操作,即不会覆盖原来的数据内容,会把你提供的对象合并到当前的 state中。
如果多个组件要实现数据共享,可以将数据提升到父组件中,对数据的操作统一在父组件中进行。
props 和 state 的相似点:
props 和 state 的不同点:
总结:state 和 props 主要的区别在于 props 是不可变的,而 state 可以根据与用户交互来改变。这就是为什么有些容器组件需要定义 state 来更新和修改数据。 而子组件只能通过 props 来传递数据。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。