React 中组件数据挂载方式-属性 props 和状态 state 说明及区别

react 中通过 props 和 state 实现组件间的通信,对数据进行传递、操作。

1. 属性 props

在组件中可以通过 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')
);

1.1 设置默认值 defaultProps

在类组件中,可以通过组件类的 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')
);

1.2 props.children

每个组件都可以获取到 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>标签中的所有内容,渲染页面的结果如下:
React porps

1.3 proptypes 类型检查

Props 验证使用 propTypes,它可以保证我们的应用组件被正确使用,React.PropTypes 提供很多验证器 (validator) 来验证传入数据是否有效。当向 props 传入无效数据时,JavaScript 控制台会抛出警告。

React.PropTypes 在 React v15.5 版本后已经移到了prop-types 库。

在终端中执行下面的命令,安装 prop-types 插件
yarn add prop-types -S

使用:

  1. 使用 import 导入 prop-types。
  2. prop-types 只能在类组件中做验证,不能在函数组件中做验证。
  3. 通过 类名.propTypes={},来定义属性规则,固定写法,注意大小写
  4. 类名.propTypes={} 中,键名为属性名,值为对属性的验证规则,例如Proptypes.string等。
  5. 可以指定一个自定义验证器。它在验证失败时应返回一个 Error 对象。自定义验证时,对象值为一个函数,函数的参数可以通过 arguments 打印。
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
  }),   

2. 状态 state

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')
);

2.1 setState()

修改 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中。

2.2 状态提升

如果多个组件要实现数据共享,可以将数据提升到父组件中,对数据的操作统一在父组件中进行。

3. 属性和状态的区别

props 和 state 的相似点:

  • 都是 js 对象,更新数据后会都会触发 render() 更新;
  • 都可以设置默认值;props 通过 defaultProps 属性设置默认值;state 直接在定义的时候设置初始值;

props 和 state 的不同点:

  • 属性是从父组件获取的,状态是在当前组件中定义的;
  • 属性值只能由父组件修改,状态值只能由当前组件修改;
  • 属性主要用于父组件和子组件间的通信,在组件内部是无法修改参数的;
  • 状态是给自己用的,在内部初始化,被自己修改,在外部是不能修改的,内部通过 setState 修改,会触发render函数;

总结:state 和 props 主要的区别在于 props 是不可变的,而 state 可以根据与用户交互来改变。这就是为什么有些容器组件需要定义 state 来更新和修改数据。 而子组件只能通过 props 来传递数据

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值