Attribute parameter transmission of component communication scheme

  • The attribute transmission scheme applies to parent-child component communication
  • When a parent component calls a child component, it passes information to the child in the form of a property (one-way data flow by default).
  • It is also possible for a child component to modify the contents of a parent component based on a callback function
    • The parent component passes a method of its own to the child component based on attributes, and the child component obtains this method and executes it, thus realizing the modification of the parent component’s information

1.1 Implement a simple voting case based on attribute parameter passing and callback function

Effect of the page

components

File directory structure

The index. The JSX code

import React from 'react';
import ReactDOM from 'react-dom';
import Vote from './componnents/Vote';
ReactDOM.render(
  <div>
    <Vote title="Do you like React?"></Vote>
  </div>.document.getElementById('root'));Copy the code

Vote. JSX code

import React from "react";
import propTypes from 'prop-types';
import VoteHeader from "./VoteHeader";
import VoteMain from "./VoteMain";
import VoteFooter from "./VoteFooter";

export default class Vote extends React.Component {
  // Set the verification property
  static defaultProps = {
    supNum: 0.oppNum: 0
  }
  static propTypes = {
    title: propTypes.string.isRequired,
    supNum: propTypes.number,
    oppNum: propTypes.number
  }
  constructor(props) {
    super(props);
    // The acquired property value is assigned to the state for later modification, and the state update component can be re-rendered
    let { supNum, oppNum } = this.props;
    this.state = {
      supNum,
      oppNum
    }
  }
  // Change the number of supports and objects
  // The arrow function is used because this is the current instance no matter where it is called
  handel = (type) = > {
    let { supNum, oppNum } = this.state;
    if (type === 'sup') {
      this.setState({ supNum: supNum + 1 })
      return
    } else {
      this.setState({ oppNum: oppNum + 1})}};render() {
    let { title } = this.props,
      { supNum, oppNum } = this.state;
    return <div className="vote-box">
      <VoteHeader title={title} supNum={supNum} oppNum={oppNum}></VoteHeader>
      <VoteMain supNum={supNum} oppNum={oppNum}></VoteMain>
      <VoteFooter callback={this.handel}></VoteFooter>
    </div>}}Copy the code

VoteHeader JSX code

import React from "react";
export default function VoteHeader(props) {
  let { title, supNum, oppNum } = props;
  return <header className="VoteHeader">
    <h2>{title}</h2>
    <span>{supNum + oppNum}</span>
  </header>
}
Copy the code

VoteMain JSX code

import React from "react";
export default function VoteMain(props) {
  let { supNum, oppNum } = props,
    total = supNum + oppNum,
    ratio = The '-';
  ratio = total <= 0 ? The '-' : `${(supNum / total * 100).toFixed(2)}% `;
  return <main className="VoteMain">
    <p>Support number: {supNum}</p>
    <p>Number of objectors: {oppNum}</p>
    <p>Support rate: {ratio}</p>
  </main>
}
Copy the code

VoteFooter JSX code

import React from "react";
import propTypes from 'prop-types'
const VoteFooter = function VoteFooter(props) {
  let { callback } = props
  return <footer className="VoteFooter">
    <button onClick={callback.bind(null, 'sup')} >support</button>
    <button onClick={()= >{callback('opp')}}> Object</button>
  </footer>
};
// Verify the format of the callback
VoteFooter.defaultProps = {
  callback: Function.prototype
}
VoteFooter.propTypes = {
  callback: propTypes.func
}
export default VoteFooter;
Copy the code

Execution context scheme of component communication scheme

When the nesting of component level is complicated, it is not very convenient to use the method of parameter passing based on attribute. At this time, we can realize the communication between components based on the scheme of execution context

  • Implement the context scheme, which applies to components that have a common ancestor element before “the outermost shell of the page can be used as the ancestor element of all components”.
  • Inside the ancestor component, mount all the information needed by the later descendant component into the context: “Can mount properties, functions, states…”
  • Within the descendant element, you can register any information you need to use

2.1 Implement simple voting function based on context scheme

components

The directory structure

Note: Traditional context implementations require ancestor components to use only class components

Steps:

  • Set the type of information in the context in the ancestor component

  • Mounting information to the context in the ancestor component “is performed both the first time and every time the component is rendered, and the context is updated with the latest properties and state values so that the information in the context is used by the descendant component is up to date.”

  • Register the function component to use “get context information inside the function component based on the second argument context”.

  • Register a class component to use theNote: The context information used in the descendant component is "registered as needed, but the type must be the same as the type in the ancestor component". This. Context can be obtained in the function

Detailed code

The index. The JSX code

import React from 'react';
import ReactDOM from 'react-dom';
import Vote from './componnents/Vote';
ReactDOM.render(
  <div>
    <Vote title="Do you like React?"></Vote>
  </div>.document.getElementById('root'));Copy the code

Vote. JSX code

import React from "react";
import propTypes from 'prop-types';
import VoteHeader from "./VoteHeader";
import VoteMain from "./VoteMain";
import VoteFooter from "./VoteFooter";
export default class Vote extends React.Component {
  // Set the verification property
  static defaultProps = {
    supNum: 0.oppNum: 0
  }
  static propTypes = {
    title: propTypes.string.isRequired,
    supNum: propTypes.number,
    oppNum: propTypes.number
  }

  // Traditional context implementation: Ancestor components are required to use only class components
  // 1. Set the type of information in the context
  static childContextTypes = {
    title: propTypes.string,
    supNum: propTypes.number,
    oppNum: propTypes.number,
    handel: propTypes.func
  }

  // 2. Mounting information to the context "is performed the first time and every time the component is rendered, and the context is updated with the latest properties and state values so that future components use the information in the context as well"
  getChildContext() {
    let { title } = this.props,
      { supNum, oppNum } = this.state;
    return {
      title,
      supNum,
      oppNum,
      handel: this.handel
    }
  }
  constructor(props) {
    super(props);
    // The acquired property value is assigned to the state for later modification, and the state update component can be re-rendered
    let { supNum, oppNum } = this.props;
    this.state = {
      supNum,
      oppNum
    }
  }
  // Change the number of supports and objects
  // The arrow function is used because this is the current instance no matter where it is called
  handel = (type) = > {
    let { supNum, oppNum } = this.state;
    if (type === 'sup') {
      this.setState({ supNum: supNum + 1 })
      return
    } else {
      this.setState({ oppNum: oppNum + 1})}};render() {
    return <div className="vote-box">
      <VoteHeader></VoteHeader>
      <VoteMain></VoteMain>
      <VoteFooter></VoteFooter>
    </div>}}Copy the code

VoteHeader JSX code

import React from "react";
import PropTypes from 'prop-types';
const VoteHeader = function VoteHeader(props, context) {
  // Get the context information inside the function component based on the second argument context
  let { title, supNum, oppNum } = context;
  return <header className="VoteHeader">
    <h2>{title}</h2>
    <span >{supNum + oppNum}</span>
  </header>
}
// Register to use
VoteHeader.contextTypes = {
  title: PropTypes.string,
  supNum: PropTypes.number,
  oppNum: PropTypes.number
}
export default VoteHeader;
Copy the code

VoteMain JSX code

import React from "react";
import PropTypes from 'prop-types'
export default class VoteMain extends React.Component {
  // The descendant component registers the context information needed to use. "Register the type as needed, but the type must be the same as the ancestor component.
  static contextTypes = {
    supNum: PropTypes.number,
    oppNum: PropTypes.number
  };
  // constructor(props) {
  // super(props);
  // }
  render() {
    let { supNum, oppNum } = this.context;
    return <main className="VoteMain">
      <p className="sup">Support number: {supNum}</p>
      <p className="opp">Number of objectors: {oppNum}</p>
    </main >
  }
}
Copy the code

VoteFooter JSX code

import React from "react";
import PropTypes from 'prop-types';
const VoteFooter = function VoteFooter(props, context) {
  let { handel } = context;
  return <footer className="VoteFooter">
    <button onClick={handel.bind(null, 'sup')} >support</button>
    <button onClick={handel.bind(null, 'opp')} >against</button>
  </footer>
};
VoteFooter.contextTypes = {
  handel: PropTypes.func
}
export default VoteFooter;
Copy the code