7. React 组件属性

这一章节讨论组件属性(亦称为props)。

组件属性是什么?

组件属性(props)的功能和 HTML attribute 类似。换句话说, props 为组件提供配置值。例如,下面代码中的 Badge 组件,当它被实例化时,它期望获取一个名为 name 的属性。

点击JSFiddle查看更多

<BadgeList> 组件里的 render 函数调用 <Badge> 组件时,name 属性会被添加到 <Badge> 组件中,类似于 HTML 属性被添加到 HTML 元素中 (比如, <Badge name="Bill" />). 然后 name 属性就可以被 Badge 组件使用了(比如,this.props.name). 这就像 <input> 元素用一个 value 属性就可以展示这个 value 了一样.

还有一种理解组件属性的方法,即这些属性都是组件的配置值。如果你看了之前 non-JSX 版本的代码示例,很明显的,组件属性只是一个对象,作为参数传送给 createElement() 函数(比如,React.createElement(Badge, { name: "Bill" }).

var Badge = React.createClass({
    displayName: "Badge",

    render: function render() {
        return React.createElement(
            "div",
            null, //no props defined, so null
            this.props.name //use passed this.prop.name as text node
        );
    }
});

var BadgeList = React.createClass({
    displayName: "BadgeList",

    render: function render() {
        return React.createElement(
            "div",
            null,
            React.createElement(Badge, { name: "Bill" }),
            React.createElement(Badge, { name: "Tom" })
        );
    }
});

ReactDOM.render(React.createElement(BadgeList, null), document.getElementById('app'));

这类似于 props 可以在 React 节点中被直接设置(参见 4.4 和 5.7)。当 createElement() 函数的参数为一个组件定义(比如,Badge),而不是一个节点时,组件属性在该组件自身中也是可用的(比如,this.props.name)。

组件属性让重用带有任何属性名的 <Badge> 组件成为可能。

在之前的代码示例中,BadgeList 组件使用了两个 Badge 组件,它们分别带有自己的 this.props 对象 。当一个 Badge 组件被实例化时,我们可以通过控制台输出 this.props 值来确定它是哪一个。

点击JSFiddle查看更多

基本上每个 React 组件实例都有一个独特的实例属性,该属性称为 props,一开始它是个空的 JavaScript 对象。这个空对象可以被父组件用 JavaScript 的 值/ 参数 填充。这些值被该组件使用或传递给子组件。

本节笔记

  • 在 ES5 环境/引擎中,你不能改变 this.props ,因为它被冻结了(比如,Object.isFrozen(this.props) === true; );
  • this.props 是只读的。

发送组件属性

给组件添加属性值时,必须是在组件被使用的时候,而不是在组件被定义的时候。比如,下面的代码中, Badge 组件首先被定义,然后再给它添加属性。当该组件被使用的时候 name=“Bill" 才被添加上去(比如,<Badge name="Bill" /> 被渲染的时候).

var Badge = React.createClass({
    render: function() {
        return <div>{this.props.name}</div>;
    }
});

ReactDOM.render(<Badge name="Bill" />, document.getElementById('app'));

组件在被调用的时候,不管在哪调用,都可以给它传递属性。

var Badge = React.createClass({
    render: function() {
        return <div>{this.props.name}</div>;
    }
});

var BadgeList = React.createClass({
    render: function() {
        return (<div>
            <Badge name="Bill" />
            <Badge name="Tom" />
        </div>);
    }
});

ReactDOM.render(<BadgeList />, document.getElementById('app'));

本节笔记

  • 组件属性是不可变的,并且组件不能够内部修改从它父级传递过来的属性。如果你一定要改变组件属性,那么该组件就要被重新渲染;不要使用 this.props.[PROP] = [NEW PROP] 这种方式来更改 props.

获取组件属性

正如 6.4 章节讨论的那样,一个组件实例可以通过 this 关键字获取任何属性值。比如,在下面的代码中,Badge 通过 this 关键字从 render 配置项中获取 props(比如,this.props.name) .

var Badge = React.createClass({
    render: function() {
        return <div>{this.props.name}</div>;
    }
});

ReactDOM.render(<Badge name="Bill" />, document.getElementById('app'));

如果你看过转化后的 Javascript (比如,JSX to JS),就没什么难掌握的。

var Badge = React.createClass({
    displayName: "Badge",

    render: function render() {
        return React.createElement(
            "div",
            null,
            this.props.name
        );
    }
});

ReactDOM.render(React.createElement(Badge, { name: "Bill" }), document.getElementById('app'));

在上面代码示例中,{ name: "Bill" } 对象连同 Badge 组件一起做为 createElement() 函数的参数。该组件可以从 props 那里了解到它的实例属性值被设置为 { name: "Bill" }.

本节笔记

  • this.props 是只读的,不要通过 this.props.PROP = ‘foo' 去设置 props。

设置默认组件属性

组件在被定义的时候,可以通过配置 getDefaultProps 来设置默认属性。 如下示例:

点击JSFiddle查看更多

如果这个组件没有其他的 prop 传递进来的话,this.props 就是默认属性。你可以用上面的代码验证下,即不带 name 属性的 Badge 组件实例使用的是默认属性 'John Doe’。

本节笔记

  • 组件被创建的时候,getDefaultProps 调用一次并被缓存。
  • 组件实例创建之前 getDefaultProps 就运行了,因此在 getDefaultProps 里使用 this.props 是没用的。
  • getDefaultProps() 返回的任何对象可以跨实例共享,但不能被复制。

组件属性不仅仅是字符串

确保要理解一个组件属性可以是任何有效的 JavaScript 值。

如下示例:

点击JSFiddle查看更多

注意当 MyComponent 被创建的时候, propArraypropObject 被新值覆盖了。

这里的要点就是当你传递属性值的时候,不要仅局限于传递字符串。

验证组件属性

定义组件的时候,propTypes 的配置项可以用来验证传递给 props 的属性值是否符合要求。如下面代码示例所示:

点击JSFiddle查看更多

如果我没有按照 propTypes 中指定的属性类型去发送属性,它就会导致错误。比如,上面的代码会在控制台中显示如下的错误:

Warning: Failed propType: Invalid prop `propArray` of type `object` supplied to `MyComponent`, expected `array`

Warning: Failed propType: Required prop `propFunc` was not specified in `MyComponent`.

Uncaught TypeError: this.props.propFunc is not a function

然而,下面正确的那个组件渲染永远都不会导致错误:

ReactDOM.render(<MyComponent propArray={[1,2]} propFunc={function(){return 3;}} />, document.getElementById('app'));

React 也提供了一些自带的验证处理(比如,React.PropTypes[VALIDATOR])(也可以创建自定义验证):

基本类型验证

这些验证检查 prop 是否是一个特殊的 JS 原生值。这些默认都是可选的。也就是说,只有设置了 prop,验证才会进行。

React.PropTypes.string 验证 prop 是否是一个字符串
React.PropTypes.bool 验证 prop 是否是一个布尔值
React.PropTypes.func 验证 prop 是否是一个函数
React.PropTypes.number 验证 prop 是否是一个数字
React.PropTypes.object 验证 prop 是否是一个对象
React.PropTypes.array 验证 prop 是否是一个数组
React.PropTypes.any 验证 prop 是否是不为空的任意类型

必要类型验证

React.PropTypes.[TYPE].isRequired 确保提供和 .isRequired 所要求的验证类型一致的 prop (e.g., propTypes:{propFunc:React.PropTypes.func.isRequired} )

元素验证

React.PropTypes.element 验证是否是一个 React 元素
React.PropTypes.node 验证是否数字,字符串,DOM 元素,或者包含以上类型的数组/片段都可以被渲染

可枚举性验证

React.PropTypes.oneOf(['Mon','Fri']) 是否是具体数值中的一个
React.PropTypes.oneOfType([React.PropTypes.string,React.PropTypes.number]) 是否是很多类型中的一种

数组或对象验证

React.PropTypes.arrayOf(React.PropTypes.number), 是否是只包含一种类型的数组
React.PropTypes.objectOf(React.PropTypes.number) 是否是只包含一种类型的对象
React.PropTypes.instanceOf(People) 是否是特定构造函数的实例(uses `instanceof`)
React.PropTypes.shape({color:React.PropTypes.string,size: React.PropTypes.number}) 是否是包含特定类型属性的对象

自定义验证

function(props, propName, componentName){} 这是你自己写的函数. 比如:

    propTypes: {
      customProp: function(props, propName, componentName) {
        if (!/matchme/.test(props[propName])) {
          return new Error('Validation failed!');
        }
      }
    }
    

results matching ""

    No results matching ""