React组件及组件之间的数据传递及函数调用

组件

组件,指的是能完成某个特定功能的独立的、可重用的代码。Component是所有组件的基类,提供了很多组件共有的功能;

React 为每个组件提供了生命周期钩子函数去相应不同的时刻-----创建时(实例化)、存在期及销毁时。

React 组件之间通信是单向的,数据只能由一方传到另一方。

组件之间的关系有:

  1. 父组件向子组件传递值
  2. 子组件向父组件传递值
  3. 兄弟组件之间通信

父组件代码

import React, { Component } from 'react';
import { Card, Row, Col, Button, Tooltip, Tabs } from 'antd';
import Children1 from './Children1';
import Children2 from './Children2';
import Children3 from './Children3';

import Context from './ChildContext';

const { TabPane } = Tabs;

class Index extends Component {
  /**
   * constructor 构造方法
   * @param props
   * ES6 对类的默认方法,通过 new 命令生成对象实例时自动调用该方法。
   * 该方法是类必有的,如果没有显示定义,则会默认添加空的 constructor()方法
   *
   * 如果想在constructor中使用this.props,super必须加props
   */
  constructor(props) {
    // todo 如果constructor中不通过super来接收props,在其他生命周期,
    // 诸如componentWillMount、componentDidMount、render中能直接使用this.props吗??
    // 结论:可以的,react在除了constructor之外的生命周期已经传入了this.props了,完全不受super(props)的影响。
    /**
     * super(props)
     * 可以不写constructor, 一旦写constructor ,就必须在函数中写super()
     * 此时组件才有自己的this, 在组件的全局中都可以实现this关键字
     * 否则如果只是constructor 而不执行super() ,那么this 指向都是错的
     */
    super(props);
    this.state = {
      msg: '父类消息',
      name: 'parent',
      index: 1,
      child3C: { key: 'child3child' },
    };
  }

  callBack = (msg, name, index) => {
    this.setState({ msg, name, index });
  };

  /**
   * 父组件 点击调用子组件2 中的函数
   * @param e
   */
  handleClick = e => {
    e.stopPropagation();
    const { msg, name, index } = this.state;
    this.children2.handleChildren2Fn(`${msg}${index}`, `${name}${index}`);
    this.setState({ index: index + 1 });
  };

  /**
   * 点击修改父组件数据,可以相应更新子组件展示数据
   * @param e
   */
  handleChangeState = e => {
    e.stopPropagation();
    const { msg, name, index } = this.state;
    this.setState({
      msg: `${msg}${index + 1}`,
      name: `${name}${index + 1}`,
      index: index + 1,
    });
  };

  /**
   * 父组件Context上下文
   * @param e
   * Provider value 属性相当于getChildContext()
   */
  handleContextBack = e => {
    e.stopPropagation();
    // const { child3C: { key: 'child3child' }, } = this.state;
    const {
      index,
      child3C: { key },
    } = this.state;
    this.setState({
      child3C: {
        key: `${key}${index + 1}`,
      },
    });
  };

  render() {
    const { msg, name, child3C } = this.state;
    return (
      
        
          
            
              
                
                  
{msg}:{name}
{ this.children2 = children; }} />
); } } export default Index;
image

一、父组件 与 子组件传递数据 Parent -> Child2

父组件向子组件传递值,可以给子组件通过props传递,自上而下进行传递。

在父组件中代码,将父组件中的state中的数据通过...展开,将父组件Parent中的信息,简洁的传递到子组件。

 {this.children2 = children;}}
/>

我在demo中将传递函数有两个按钮,“P调用C2函数” 与 “P函数修改数据,同步C2数据”

按钮“P调用C2函数” 与 “P函数修改数据,同步C2数据”

1、 P函数修改数据,同步C2数据


这个按钮式,修改Parent数据,然后同步Children2的数据,点击按钮,调用onClick函数,此函数点击修改父组件数据,可以相应更新子组件展示数据。

父组件的props与state改变会导致子组件的生命周期发生变化,更新子组件数据。

/**
   * 点击修改父组件数据,可以相应更新子组件展示数据
   * @param e
   */
  handleChangeState = e => {
    e.stopPropagation();
    const { msg, name, index } = this.state;
    this.setState({
      msg: `${msg}${index + 1}`,
      name: `${name}${index + 1}`,
      index: index + 1,
    });
  };

在子组件children2中,可以通过this.props 获取,如下 子组件2 代码。

image
image

2、 P调用C2函数 父组件调用子组件函数 (也是子组件传递函数到父组件)

父组件 点击调用子组件2 中的函数。由于组件之间通信是单向的,父组件可以传递给子组件,但是如果父组件需要调用子组件函数,需要进行特殊处理。

子组件2中定义函数,this 指向 children2

handleChildren2Fn = (msg, name) => {
   this.setState({ msg, name });
};

在父组件

 {this.children2 = children;}}/>

使用ref 方法。ref 方法可以接收一个回调函数,表示子组件加载完成之后执行的方法,回调函数的参数即为子组件的作用域this,把子组件的作用域this赋值给父组件,就可以用用子组件中的方法了。

/**
   * 父组件 点击调用子组件2 中的函数
   * @param e
   */
  handleClick = e => {
    e.stopPropagation();
    const { msg, name, index } = this.state;
    this.children2.handleChildren2Fn(`${msg}${index}`, `${name}${index}`);
    this.setState({ index: index + 1 });
  };

子组件2代码

import React, { Component } from 'react';
import { Card } from 'antd';
import isEqual from 'lodash/isEqual';

class Children2 extends Component {
  constructor(props) {
    super(props);
    this.state = {
      name: 'children2',
      msg: 'children2 消息',
      pName: props.name,
      pMsg: props.msg,
    };
  }

  /**
   * getDerivedStateFromProps react17 新的生命周期
   * 用于替换 componentWillReceiveProps ,用来控制props 更新 state的过程,他返回一个对象表示新的state.
   * 每次渲染之前都会调用,不管初始挂载还是后面的 更新,都会调用,
   * componentWillReceiveProps 只有父组件早场重新渲染才会调用
   * 执行 setState 也会触发此函数
   *
   * static 中不允许用this
   *
   * 由于getDerivedStateFromProps 会在setState()后被调用,
   * 并且它的返回值会被用于更新数据, 这意味着会在测触发setState()
   * nextProps 第一个位置上的参数,未必是“新的” props,在组建中调用setState() 时,
   * getDerivedStateFromProps 会被调用,此时nextprops并不是最新的。
   *
   *
   * @param nextProps
   * @param preState
   * @returns {*}
   */
  static getDerivedStateFromProps(nextProps, preState) {
    if (isEqual(nextProps.msg, preState.msg)) {
      return null;
    }
    const { msg, name, index } = nextProps;
    return { pMsg: msg, pName: name, index };
  }

  handleChildren2Fn = (msg, name) => {
    // console.log('调用children2 消息=========');
    // console.log(this);
    this.setState({ msg, name });
  };

  render() {
    const { name, msg, pMsg, pName } = this.state;
    return (
      
        
{pMsg} : {pName}
{msg} : {name}
); } } export default Children2;

二、子组件 -> 传递数据 到父组件

子组件1代码

import React, { Component } from 'react';
import { Card, Button } from 'antd';

class Children1 extends Component {
  constructor(props) {
    super(props);
    this.state = {
      name: 'children1',
      msg: 'children1 消息',
      pName: props.name,
      pMsg: props.msg,
    };
  }

  /**
   * handleClick 采用箭头函数的写法,目的是改变this的指向,
   * 使得在函数单独调用的时候,函数内部的this依然指向children1 组件
   * @param msg
   * @param name
   */
  handleClick = () => {
    // console.log(this);
    const { name, msg } = this.state;
    this.props.callBack(msg, name);
  };
  
  render() {
    const { name, msg, pMsg, pName } = this.state;
    return (
      
        
{pMsg} : {pName}
{msg} : {name}
); } } export default Children1;

如图所示,父组件、子组件一、子组件二

image

你可能感兴趣的:(React组件及组件之间的数据传递及函数调用)