如果你觉得还是搞不清 state 和 props 的使用场景,那么请记住一个简单的规则:尽量少地用 state,尽量多地用 props。 没有 state 的组件叫无状态组件(stateless component),设置了 state 的叫做有状态组件(stateful component)。因为状态会带来管理的复杂性,我们尽量多地写无状态组件,尽量少地写有状态的组件。这样会降低代码维护的难度,也会在一定程度上增强组件的可复用性。函数式组件就只有props没有state,而react也非常鼓励我们编写函数式组件。
Props 和 State 本质
props 是组件对外的接口,state 是组件对内的接口。组件内可以引用其他组件,组件之间的引用形成了一个树状结构(组件树),如果下层组件需要使用上层组件的数据或方法,上层组件就可以通过下层组件的props属性进行传递,因此props是组件对外的接口。组件除了使用上层组件传递的数据外,自身也可能需要维护管理数据,这就是组件对内的接口state。根据对外接口props 和对内接口state,组件计算出对应界面的UI。
组件的props 和 state都和组件最终渲染出的UI直接相关。两者的主要区别是:state是可变的,是组件内部维护的一组用于反映组件UI变化的状态集合;而props是组件的只读属性,组件内部不能直接修改props,要想修改props,只能在该组件的上层组件中修改。在组件状态上移的场景中,父组件正是通过子组件的props,传递给子组件其所需要的状态。
定义默认属性Props:
1)以 类名.defaultProps 属性的方式定义
import React, {PureComponent} from "react"
import NwdInput from "component/nwd-input/index.js"
import {BrowserRouter as Router, Route, Link} from 'react-router-dom'
export default class Life extends React.Component {
constructor(props) {
super(props)
console.log(this.props)
}
render() {
return (
<div>
<NwdInput></NwdInput>
</div>
)
}
}
Life.defaultProps = {
name: "xxxx"
}复制代码
输出
注释: 不被推荐的使用方式,但是简单直接有效
2)静态变量传参的方式
import React, {PureComponent} from "react"
import NwdInput from "component/nwd-input/index.js"
import {BrowserRouter as Router, Route, Link} from 'react-router-dom'
export default class Life extends React.Component {
constructor(props) {
super(props)
console.log(this.props)
}
static defaultProps = {
name: "xxxxxxxx"
}
render() {
return (
<div>
<NwdInput></NwdInput>
</div>
)
}
}复制代码
输入如下
注释: 使用静态属性,传参给 构造函数,推荐使用
多个值(属性)传递:
父组件属性传递到子组件,这是一个属性的传递,那么如何传递多个属性值呢?
父组件
render() {
return (
<div>
<NwdInput name1={"你我贷1"} name2={"你我贷2"}></NwdInput>
</div>
)
}复制代码
子组件
import React, {PureComponent} from "react"
import {PropTypes} from 'prop-types';
export default class NwdInput extends React.Component {
constructor(props) {
super(props)
console.log(this.props)
}
render() {
return (
<input/>
)
}
}复制代码
输出如下
但是上面的写法有点累赘,推荐方法如下
我们使用JSX的扩展语法来传递属性值,也就是...语法
父组件
render() {
var nameProps = {
name1: "你我贷1",
name2: "你我贷2"
}
return (
<div>
<NwdInput names = {{...nameProps}}></NwdInput>
</div>
)
}复制代码
子组件
import React, {PureComponent} from "react"
import {PropTypes} from 'prop-types';
export default class NwdInput extends React.Component {
constructor(props) {
super(props)
}
render() {
console.log(this.props)
return (
<input/>
)
}
}复制代码
输出如下
属性校验:
在React中属性是可以校验的,React中使用propTypes进行校验
import React, {PureComponent} from "react"
import NwdInput from "component/nwd-input/index.js"
import {PropTypes} from 'prop-types';
import {BrowserRouter as Router, Route, Link} from 'react-router-dom'
export default class Life extends React.Component {
constructor(props) {
super(props)
}
static defaultProps = {
sex: 111
}
static propTypes = {
sex:PropTypes.string
}
render() {
return (
<div>
<div>{this.props.sex}</div>
</div>
)
}
}复制代码
this.props.children
Props中有一个特殊的属性props.children可以允许我们使用子组件
注意:在当前组件内,你直接输出this.props.children是得不到任何信息的,会返回undefined,因为该属性是组件的拥有者传递过来的信息,所以,只能在渲染组件的时候进行输出。
子组件
import React, {PureComponent} from "react"
import {PropTypes} from 'prop-types';
export default class NwdList extends React.Component {
constructor(props) {
super(props)
}
render() {
return (
<div>
<ul>
{this.props.children}
</ul>
</div>
)
}
}复制代码
父组件
import React, {PureComponent} from "react"
import NwdList from "component/nwd-list/index.js"
import {PropTypes} from 'prop-types';
import {BrowserRouter as Router, Route, Link} from 'react-router-dom'
export default class Life extends React.Component {
constructor(props) {
super(props)
}
state = {
user: 1111,
}
static defaultProps = {
sex: "男"
}
static propTypes = {
sex:PropTypes.string
}
render() {
return (
<div>
<NwdList>
<li>{this.props.sex}</li>
</NwdList>
</div>
)
}
}复制代码
输出如下
注意:如果我们不主动在NwdList组件的render函数中设置{this.props.children},那么li标签是不会被渲染出来的。除了Props之外,另一个隐性的组件的输入即是context,整个React组件树会拥有一个context对象,它可以被树中挂载的每个组件所访问到。
this.props.children 的值有三种可能:
1) 如果当前组件没有子节点,它就是 undefined ;
2) 如果有一个子节点,数据类型是 object ;
3) 如果有多个子节点,数据类型就是 array 。
而使用 React.Children.map 来遍历子节点,就不必担心 this.props.children 的数据类型是 undefined 还是 object。
子组件
import React, {PureComponent} from "react"
import {PropTypes} from 'prop-types';
export default class NwdList extends React.Component {
constructor(props) {
super(props)
}
render() {
console.log(this.props.children)
return (
<div>
<ul>
{
React.Children.map(this.props.children,function(child) {
return <li>{child}</li>
})
}
</ul>
</div>
)
}
}复制代码
父组件
import React, {PureComponent} from "react"
import NwdList from "component/nwd-list/index.js"
import {PropTypes} from 'prop-types';
import {BrowserRouter as Router, Route, Link} from 'react-router-dom'
export default class Life extends React.Component {
constructor(props) {
super(props)
}
state = {
user: 1111,
}
static defaultProps = {
sex: "男"
}
static propTypes = {
sex:PropTypes.string
}
render() {
return (
<div>
<NwdList>
{this.props.sex}
</NwdList>
</div>
)
}
}复制代码
输出如下