react父子组件-05

2019-12-07  本文已影响0人  逝去丶浅秋

react的组件是解决html标签构建应用的不足,它的好处是能把公共的功能单独抽离成一个文件作为一个组件,哪里需要就在哪里引入。
父子组件:组件的相互调用中,把调用者称为父组件,被调用者称为子组件。

一、父组件向子组件传值

在父组件引入子组件:

import ChildComponent from './ChildComponent';
1、传递值

父组件向子组件传值,在子组件标签里设置一个属性传递,例如data:<ChildComponent data={this.state.data}/>。
在子组件中通过this.props.data来获取,如附1代码。

2、传递方法

父组件向子组件传方法,在子组件标签设置一个属性传递,例如run:<ChildComponent run={this.run}/>。
在子组件里通过this.props来调用run方法,如附1代码。

3、传递整个组件

将整个父组件传给子组件,在子组件标签设置一个属性传递,例如parentCpt:<ChildComponent parentCpt={this}/>。
在子组件的方法里通过this.props.parentCpt来调用getParent,也可以调用state里的值,使用this.props.parentCpt.state,如附1代码。

传递其他的组件:

const Bar = <p>我是Bar组件</p>; //或
const Bar =()=> (<p>我是Bar组件</p>);
<ChildComponent component={Bar} /> //或
<ChildComponent component={<Bar/>} />
在子组件中:
{this.props.component}获取

const Bar =()=> (<p>我是Bar组件</p>);
<ChildComponent component={()=><Bar/>} />
传递的component是个方法,在调用时需要写成component()让其执行
在子组件中:
{this.props.component()}获取

二、子组件向父组件传值

1、传递值

通过this.props.parentCpt.getChildData.bind(this,this.state.changeMsg);来把值传到父组件的getChildData方法中,来改变父组件的值,如附1代码。

2、父组件中获取子组件的方法或值

在父组件中的子组件标签添加ref属性:<ChildComponent ref="childCpt"/>,父组件通过this.refs来获取子组件的方法和值,见附1代码父组件中的getChildRun方法。

三、propTypes和defaultProps

defaultProps:父子组件传值中,如果父组件调用子组件的时候不给子组件传值,则可以在子组件中使用defaultProps定义的默认值。
propTypes:验证父组件传值的类型合法性。

1、defaultProps的用法

在子组件中使用子组件名称调用defaultProps添加默认值:

// 父子组件传值中defaultProps的用法
ChildComponent.defaultProps={
    propsData:"父子组件传值的默认值"
}

defaultProps属性需要在组件外进行调用,写在组件(class 组件{})中会报错。
然后子组件中使用this.props.propsData调用这个默认值。具体代码见附件1中所示。

2、propTypes的用法

关于propTypes更多用法可以参见React官方文档:https://zh-hans.reactjs.org/docs/typechecking-with-proptypes.html
propTypes进行的类型检查,出于性能方面的考虑,仅在开发模式下进行检查,在JavaScript控制台将会显示警告,但是不会在页面上报错,所以开发时要看控制台中类型是否错了。需要注意的是这个检查也要写在组件外。

ChildComponent.propTypes = {
    propsData:PropTypes.number.isRequired
}

此处的propsData是个字符串,这里检查是否为number则会报错,报错如下:

Warning: Failed prop type: Invalid prop `propsData` of type `string` supplied to `ChildComponent`, expected `number`.
    in ChildComponent (at ParentComponent.js:43)
    in ParentComponent (at App.js:25)
    in div (at App.js:16)
    in App (at src/index.js:8)

其中的isRequired为设置属性为必须传递的值。
下面附2为可以检查的类型。
附1:父子组件代码如下:

import React from 'react';
//引入子组件
import ChildComponent from './ChildComponent';

class ParentComponent extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            msg:"这是父组件",
            data:"[父组件的数据]"
        };
    }
    run=()=>{
        alert("父组件的run方法执行")
    }
    getParent=()=>{
        alert("获取到父组件未传递的方法")
    }
    getChildData=(childData)=>{
        this.setState({
            msg:childData
        })
    }
    getChildRun=()=>{
        this.refs.childCpt.run();
        this.refs.childCpt.getParentComponent();
        this.setState({
            msg:this.refs.childCpt.state.msg
        })
    }

    render() {
        return (
            <div>
            <hr style={{border:"1px solid"}}/>

                <h2>这是父组件</h2>
                {/* 父组件向子组件传值,在子组件标签里设置一个属性传递,例如data,通过this.state.data获取要传递的值
                    父组件向子组件传方法,在子组件标签设置一个属性传递,例如run,通过this.run获取要传递的方法
                    将整个父组件传给子组件,在子组件标签设置一个属性传递,例如parentCpt,通过this,即整个组件
                */}
                {/* 在子组件标签上添加ref,父组件通过this.refs来获取子组件的方法和值 */}
                <ChildComponent ref="childCpt" data={this.state.data} run={this.run} parentCpt={this}/>

                <button onClick={this.getChildRun}>父组件获取子组件的方法</button>
                <br/><span>父组件当前msg值:{this.state.msg}</span>

            <hr style={{border:"1px solid"}}/>           
            </div>
        );
    }
}

export default ParentComponent;
import React from 'react';

class ChildComponent extends React.Component {
    constructor(props) {
        super(props);
        this.state = { 
            msg:"这是子组件",
            data:"[子组件的数据]",
            changeMsg:"changeMsg--->父组件值被改变"
         };
    }
    run=()=>{
        alert("子组件的run方法")
    }
    getParentComponent=()=>{
        this.props.parentCpt.getParent();
        alert("父组件里的msg--->"+this.props.parentCpt.state.msg);
        alert("父组件里的msg--->"+this.props.parentCpt.state.data);
    }
    render() {
        return (
            <div>
                <hr style={{border:"1px dashed"}}/>
                <h2>这是子组件</h2>
                {/* 父组件向子组件传值,在子组件里通过this.props来调用data */}
                <span>父组件向子组件传的值:{this.props.data}</span>
                {/* 父组件向子组件传方法,在子组件里通过this.props来调用run */}
                <button onClick={this.props.run}>点击执行父组件的run方法</button>
                {/* 父组件向子组件传整个组件,
                    在子组件的方法里通过this.props.parentCpt来调用getParent,
                    也可以调用state里的值,使用this.props.parentCpt.state */}
                <button onClick={this.getParentComponent}>
                        点击执行未传递的父组件的getParent方法
               </button>
                
                {/* 子组件向父组件传值 */}
                <button onClick={this.props.parentCpt.getChildData.bind(this,this.state.changeMsg)}>
                    子组件给父组件传changeMsg值
                </button>

                {/* 父子组件传值中的默认值defaultProps */}
                <br/><span>父子组件传值中的defaultProps值:{this.props.propsData}</span>
            <hr style={{border:"1px dashed"}}/>
            </div>
            
        );
    }
}

// 父子组件传值中defaultProps的用法
ChildComponent.defaultProps={
    propsData:"父子组件传值的默认值"
}

export default ChildComponent;

附2:propTypes可检查类型:

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 properties
  //即在附加属性上带有警告的对象
  optionalObjectWithStrictShape: PropTypes.exact({
    name: PropTypes.string,
    quantity: PropTypes.number
  }),   

  // 你可以在任何 PropTypes 属性后面加上 `isRequired` ,确保
  // 这个 prop 没有被提供时,会打印警告信息。
  requiredFunc: PropTypes.func.isRequired,

  // 任意类型的数据
  requiredAny: PropTypes.any.isRequired,

  // 你可以指定一个自定义验证器。它在验证失败时应返回一个 Error 对象。
  // 请不要使用 `console.warn` 或抛出异常,因为这在 `onOfType` 中不会起作用。
  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.'
      );
    }
  })
};

写在最后:

上一篇下一篇

猜你喜欢

热点阅读