react 组件之间的通信(父子组件)

一、父子组件

React中 组件内调用其他组件不需要进行 类似于vue 声明组件(components)

React 组件内调用其他组件 直接将组件导入 放置在对应的JSX 代码中

父子组件通信(传统):

1、父组件->子组件  通过属性传递

2、子组件->父组件  父组件通过将自身的函数对象传递给子组件, 子组件执行父组件传递的函数来修改/传值操作

练习一:

Father:

import { Component } from 'react'

import Son from './Son';

class Father extends Component {

  /* constructor(props){
    super(props);

    this.state = {
      person: {
        name: '张三',
        age: 200
      }
    }
  }
 */
  state = {
    person: {
      name: '张三',
      age: 200
    },

    arr: [1,2,3]
  }

  render() {
    return (
      <div className='container'>
        <h1>Father组件:</h1>
        <ul>
          {
            this.state.arr.map( item => (
              <li key={item}>{item}</li>
            ) )
          }
        </ul>

        <hr/>

        {/* 
          通过 自定义属性 vperson 将 this.state.person 传递给 Son
        
          const vadd = (e, item) => this.handleAddArray(e.vitem);

          vadd(event, 1000)
        */}
        <Son vperson={this.state.person} varr={this.state.arr} vhandle={this.handleAge.bind(this)} vadd={ (e, vitem) => this.handleAddArray(e, vitem)}/>
      </div>
    )
  }


  handleAge(){

    this.setState({
      person: {...this.state.person, age: this.state.person.age +1 }
    });
  }

  handleAddArray(e, item){
    console.log('子组件调用父组件 handleAddArray..........');
    // 向 arr 中末尾追加新元素
    this.state.arr.push(item);

    this.setState({
      arr: this.state.arr
    });

  }
}

export default Father;

Son:

import { Component } from 'react'

class Son extends Component {

  /* 
  子组件 通过constructor 函数中的props 形参 接受 父组件 传递的所有属性

  注: 子组件内不允许修改/更新 父组件所传递的 props
  */
  constructor(props){
    super(props);

    console.log('Son props=>', props);

  }

  render() {
    const {  vperson  } = this.props;
    return (
      <div>
        <h1 className="h1">Son</h1>
        <h3 className='h3'>
        {/*   {this.props.vperson.name}
          {this.props.varr} */}
  
          {vperson.name} --- {vperson.age}
        </h3>
        <button className="btn btn-primary" onClick={this.add.bind(this)}>增加年龄</button>

        <button className="btn btn-success" onClick={this.localadd.bind(this)}>增加arr数组元素</button>

      </div>
    )
  }

  add(){
    // 调用父组件传递的 handleAge 函数
    this.props.vhandle();
  }

  localadd(e){
    this.props.vadd(e, new Date().getTime());
  }
}

export default Son;

练习二:

Father:

import { Component } from 'react'

import Son from './Son';

class Father extends Component {

  state = {
    tabs : [
      {
        tid: '001',
        title: '我的',
        isActive: true
      },
      {
        tid: '002',
        title: '收藏',
        isActive: false
      },
      {
        tid: '003',
        title: '设置',
        isActive: false
      }
    ]
  }

  render() {
    const {tabs} = this.state;
    return (
      <div className="container">
        <h1>Father组件</h1>
        <hr/>
        <Son tabsProps={tabs}  changeItem={ selectedId => this.changeItem(selectedId) }/>
      </div>
    )
  }

  changeItem(selectedID){
    console.log('子组件调用父组件 changeItem 获取tab id=>', selectedID);

    // 根据 selectedID 值 匹配 this.tabs 数组中的元素 如果匹配修改isActive=true 如果不匹配 isActive=false

    this.state.tabs.forEach( item => {
      if(item.tid === selectedID) item.isActive = true;
      else item.isActive = false;
    } )

    this.setState({
      tabs: this.state.tabs
    });
  }
}

export default Father

Son:

import { Component } from 'react'

/* 
子组件接受 props 可以省略 constructor函数接受props , 直接通过 this.props获取父组件传递的属性值
*/
class Son extends Component {
  render() {
    return (
      <div>
        <h1 className="h1">Son组件</h1>

        <div className="d-flex flex-column">
          <div className="btns fs-3 text-center  w-50 d-flex justify-content-around">
           {/*  <div className="w-25 bg-danger">我的</div>
            <div className="w-25">收藏</div>
            <div className="w-25">设置</div> */}

            {
              this.props.tabsProps.map( tab => (
                <div className={'w-25 '+(tab.isActive ? 'bg-danger': '')} key={tab.tid} onClick={this.selecteItem.bind(this, tab.tid)}>{tab.title}</div>
              ) )
            }
          </div>
          <div className="content">
            {
              this.props.tabsProps.find( tab => tab.isActive ).title
            }
          </div>
        </div>
      </div>
    )
  }

  selecteItem(selectedID){
    console.log('选择tab id=>', selectedID);
    this.props.changeItem(selectedID);
  }
}

export default Son

练习三:

props 数据类型校验 写法有两种:

1、在当前的类中定义 一个静态变量  static propTypes(该变量名称不允许随意修改)

2、在当前的类之外 定义一个静态变量  类名.propTypes(该变量名称不允许随意修改)

Father:

import { Component } from 'react';

import Son from './Son'

/* 
props 数据类型检测
*/

class Father extends Component {

  state = {
    num: 100,
    msg: 'Hello',
    arr: [],
    isFlag: true
  }
  render() {
    const { num ,msg, arr, isFlag } = this.state;
    return (
      <div>
        <h1>Father:</h1>
        <hr/>
        <Son pnum={num} pmsg={msg}  pisFlag={isFlag}/>
      </div>
    )
  }
}

export default Father

Son:

import React, { Component } from 'react';

import FatherPropTypes from 'prop-types';


class Son extends Component {

  /* static propTypes = {
    pnum: FatherPropTypes.number, //数据类型 number
    pmsg: FatherPropTypes.string,
    parr: FatherPropTypes.array.isRequired, //必填属性
    pisFlag: FatherPropTypes.bool
  } */

  render() {
    const {pnum, pmsg, parr, pisFlag} = this.props;
    return (
      <div>
        <h1>Son:</h1>
        <h6>pnum:{pnum}</h6>
        <h6>pmsg:{pmsg}</h6>
        <h6>parr:{parr}</h6>
        <h6>pisFlag:{pisFlag}</h6>
      </div>
    )
  }
}

Son.propTypes = {
  pnum: FatherPropTypes.number, //数据类型 number
  pmsg: FatherPropTypes.string,
  parr: FatherPropTypes.array.isRequired, //必填属性
  pisFlag: FatherPropTypes.bool
}


export default Son;

练习四:

props 默认值设置 写法有两种:

1、在当前的类中定义 一个静态变量  static defaultProps(该变量名称不允许随意修改)

2、在当前的类之外 定义一个静态变量  类名.defaultProps(该变量名称不允许随意修改)

什么时候调用默认值:

1、传递的prop 原本的值为 undefined 则调用 默认值

2、没有传递 prop 则调用 默认值

Father:

import { Component } from 'react';

import Son from './Son'

/* 
props 默认值设置
*/

class Father extends Component {

  state = {
    num: undefined,
    msg: undefined,
    arr: undefined,
    isFlag: undefined
  }
  render() {
    const { num ,msg, arr, isFlag } = this.state;
    return (
      <div>
        <h1>Father:</h1>
        <hr/>
        <Son pnum={num} pmsg={msg} parr={arr} pisFlag={isFlag}/>
      </div>
    )
  }
}

export default Father

Son:

import React, { Component } from 'react';



class Son extends Component {

  /* static defaultProps = {
    pnum: -1,    //FatherPropTypes.number, //数据类型 number
    pmsg: '没有文字',//FatherPropTypes.string,
    parr:  [-100, -200, -300],//FatherPropTypes.array.isRequired, //必填属性
    pisFlag: false
  } */

  render() {
    const {pnum, pmsg, parr, pisFlag} = this.props;
    return (
      <div>
        <h1>Son:</h1>
        <h6>pnum:{pnum}</h6>
        <h6>pmsg:{pmsg}</h6>
        <h6>parr:{parr}</h6>
        <h6>pisFlag:{pisFlag}</h6>
      </div>
    )
  }
}

Son.defaultProps = {
  pnum: -1,    //FatherPropTypes.number, //数据类型 number
    pmsg: '没有文字',//FatherPropTypes.string,
    parr:  [-100, -200, -300],//FatherPropTypes.array.isRequired, //必填属性
    pisFlag: false
}


export default Son;

Son1:

import PropTypes from 'prop-types'
import { Component } from 'react'

/* 
props 进行类型检测与默认值设置
*/

class Son1 extends Component {
  static propTypes = {}

  static defaultProps = {}

  render() {
    return (
      <div>Son1</div>
    )
  }
}

export default Son1

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值