React之组件(component)之间的通讯----props、context

组件通讯

  • 组件是独立封闭的单元
  • 一个完整的页面通常是由多个组件组合而成的
  • 组件之间经常需要共享一些数据,所以就需要组件之间能够通讯

props

  • props 用于接收外界向组件中传递的数据

实现方法

  • 渲染组件时,在组件标签中使用自定义属性向组件内部传递数据
  • 组件内部可以使用 props 来接收自定义属性传递的数据
    • 函数组件: props
    • 类组件: this.props

注意事项

  • 除了字符串之外,其他类型的数据都需要使用 {}
  • props 是只读属性,不能修改里面的数据
  • 使用类组件时,如果写了构造函数,则需要将 props 传递给 super(),否则在 constructor 中无法使用props (其他方法可以使用)

类组件中接收自定义属性中的数据

类组件方式1:

import React from 'react'
import ReactDOM from 'react-dom'

class App extends React.Component{
    
    
  render () {
    
    
    return (
      <div>
        大家好,我叫{
    
    this.props.name},今年{
    
    this.props.age}</div>
    )
  }
}

ReactDOM.render(<App name='zs' age={
    
    18} />,document.querySelector('#app'))

组件内部会议对象形式将数据保存在props属性中

this.props = {
    
    
	name:'zs',
	age: 18
}

调用组件时,使用自定义属性将数据传递到组件内部
this.props.name this,props.age

类组件方式2:

如果写了构造函数,则需要将props传递给super(),否则在constructor中无法使用props(其他方法可以使用)

import React from 'react'
import ReactDOM from 'react-dom'

class App extends React.Component{
    
    
  constructor (props) {
    
    
    super(props)
    //console.log(this.props)
  }
  render () {
    
    
    return (
      <div>
        大家好,我叫{
    
    this.props.name},今年{
    
    this.props.age}</div>
    )
  }
}

ReactDOM.render(<App name='zs' age={
    
    18} />,document.querySelector('#app'))

函数组件中接收自定义属性中的数据

import React from 'react'
import ReactDOM from 'react-dom'

const App = (props) => {
    
    
  reyurn (
      <div>
        大家好,我叫{
    
    props.name},今年{
    
    props.age}</div>
  )
}

ReactDOM.render(<App name='zs' age={
    
    18} />,document.querySelector('#app'))

父子组件嵌套

在一个组件中可以嵌套另一个组件,外层的组件就是父组件,内层的组件就是子组件

实现方法: 父组件的== render 方法==中调用子组件

import React from 'react';
import ReactDOM from 'react-dom';

import './assets/css/fs.css'

// 创建子组件
class Son extends React.Component {
    
    
  render () {
    
    
    return (
      <div className="son">我是子组件</div>
    )
  }
}

// 创建父组件
class Father extends React.Component {
    
    
  render () {
    
    
    return (
      <div className="father">
        <div>我是父组件</div>
        {
    
    /* 父组件在render方法中渲染子组件 */}
        <Son />
      </div>
    )
  }
}

ReactDOM.render(<Father />, document.querySelector('#app'))

在这里插入图片描述

父向子传值

父组件渲染子组件时,将state中的数据添加到子组件的自定义属性中
在这里插入图片描述

实现要点:

  1. 父组件要有state,内部保存准备传递给子组件的数据
  2. 父组件调用子组件时,为子组件添加自定义属性,将 state 中的数据设置为属性的值
  3. 子组件中使用props接收父组件数据
import React from 'react'
import ReactDOM from 'react-dom'
import './assets/css/fs.css'

// 目标: 子组件接收到父组件的数据

class Son extends React.Component {
    
    
  render () {
    
    
    return (
      <div className="son">
        我是子组件<br />
        {
    
    /* 子组件使用 props 来接收父组件数据 */}
        接收到父组件的数据为: {
    
    this.props.name} - {
    
    this.props.age}
      </div>
    )
  }
}

class Father extends React.Component {
    
    
  state = {
    
    
    name: '二狗子',
    age: 8
  }
  render () {
    
    
    return (
      <div className="father">
        我是父组件
        {
    
    /* 父组件在调用子组件时,将数据通过自定义属性传递给子组件 */}
        <Son name={
    
    this.state.name} age={
    
    this.state.age} />
      </div>
    )
  }
}

ReactDOM.render(<Father />, document.querySelector('#app'))

子向父传值

核心: 利用回调函数

  1. 父组件
    1. 父组件中创建一个接收子组件数据的函数
    2. 父组件调用子组件时,将函数作为参数传给子组件
  2. 子组件 (子组件已经将父组件函数保存在 props 中
    1. 子组件中使用 state 定义要传递给父组件的数据
    2. 子组件利用事件调用父组件传递的函数,并将数组作为参数传入
import React from 'react'
import ReactDOM from 'react-dom'
import './assets/css/fs.css'

// 目标: 将子组件中的数据传递到父组件中

class Son extends React.Component {
    
    
  state = {
    
    
    name: '翠花',
    age: 18
  }
  handleClick = () =>{
    
    
    console.log('click')
    console.log(this.props.name)
    this.props.fn(this.state)
  }
  render () {
    
    
    return (
      <div className="sdiv">
        <div>我是子组件</div>
        <button onClick={
    
    this.handleClick}>发送</button>
      </div>
    )
  }
}

class Father extends React.Component {
    
    
  getChildData = (data) =>{
    
    
    console.log("getChildData:",data)
  }
  render () {
    
    
    return (
      <div className="fdiv">
        <div>我是父组件</div>
        <Son name="zs" age={
    
    18} fn={
    
    this.getChildData}/>
      </div>
    )
  }
}

ReactDOM.render(<Father />, document.querySelector('#app'))

兄弟组件传值

思路: 子向父传值 、 父向子传值 两步的结合

  • 子组件B 通过调用父组件的函数将数据传递给父组件 (子向父传值)
  • 父组件再通过子组件属性向子组件A传值 (父向子传值)

核心名词: 状态提升

状态提升:将数据统一放在父组件中进行保存,父组件既要提供state保存数据,也要提供方法,让子组件能向父组件进行传值

Context解决的问题
在这里插入图片描述

Context

  1. 传统方式缺陷明显,一层一层传递太过复杂
  2. 解决方案: 使用 Context 可以实现跨组件传值
  3. 实现步骤:
  • 调用 React.createContext() 方法创建 Provider (提供数据) 和 Consumer (消费数据)
  • 使用 Provider 组件包裹最外层的父组件,并使用 value属性传递数据
  • 使用 Consumer 接收数据
import React from 'react'
import ReactDOM from 'react-dom'
import './css/context.css'

//1. 调用 React.createContext() 方法创建 Provider 和 Consumer 两个组件
const {
    
    Provider, Consumer} = React.createContext()

class App extends React.Component {
    
    
  state = {
    
    
    msg: '我是 App.state.msg 的数组'
  }

  render () {
    
    
    return (
      //2. 使用 Provider 组件包裹整个组件, 使用 value 属性传递数据
      <Provider value={
    
    this.state.msg}>
        <div className="app">
          App组件
          <Child />
        </div>
      </Provider>
    )
  }
}

const Child = () => {
    
    
  return (
    <div className="child">
      Child组件
      <SubChild />  
    </div>
  )
}

const SubChild = () => {
    
    
  return (
      <div className="subchild">SubChild组件:
        {
    
    /* 3. 使用 Consumer 组件来接收 Provider 提供的数据 */}
        <Consumer>
          {
    
    data => <span>{
    
    data}</span>}
        </Consumer>
      </div>
  )
}

ReactDOM.render(<App />, document.querySelector('#app'))

Consumer 中是一个函数,参数data中就保存了Provider中value提供的数据

props其他功能

children 属性

  • render 方法在渲染组件标签时可以使用双标签
  • 组件使用双标签时,内部可以填入子节点,例如:文本子节点、标签子节点、JSX子节点、函数子节点
  • props.children 中以数组形式保存这些子节点
import React from 'react'
import ReactDOM from 'react-dom'

class Show extends React.Component {
    
    
  render () {
    
    
    return (
      <div>我是show</div>
    )
  }
}

class App extends React.Component {
    
    
  render () {
    
    
    // App组件子节点的信息都保存在 this.props.children 属性中
    console.log(this.props)
    return (
      <div>我是App组件</div>
    )
  }
}

ReactDOM.render(
  <App>
    <h1>我是写在App中的内容</h1>
    <Show>哈哈哈</Show>
    <div>
      {
    
    
        () => {
    
    
          console.log('兄弟12345')
        }
      }
    </div>
  </App>, 
  document.querySelector('#app')
)

props校验

  • props用来接收外来数据,这些数据可以在组件中被使用
  • 但是组件的调用者可能会传入一些不符合规则的数据
  • 当组件调用者传入不符合规则的数据时,用该进行错误提示

props校验的目标: 让组件的调用者清楚的知道,调用组件时产生错误的原因

解决方案: 使用 prop-types 第三方包

使用步骤:

  1. 安装 prop-types: npm i prop-types

  2. 导入 prop-types 包

  3. 为组件添加propTypes验证

//1. 导入 prop-types 包
import PropTypes from 'prop-types'

//2. 为组件添加验证
App.propTypes = {
    
    
   color: PropTypes.array
}

在这里插入图片描述
常见校验规则

  • 常见数据类型: array、bool、func、number、object、string
  • React元素类型: element
  • 必填项: isRequired
  • 特定结构: shape({})
import React from 'react'
import ReactDOM from 'react-dom'


import PropTypes from 'prop-types'

class App extends React.Component {
    
    
  render () {
    
    
    console.log(this.props)
    return (
      <div>哈哈</div>
    )
  }
}

// 属性 name 类型为字符串,必填
// 属性 age  类型为数值
// 属性 hobbies 类型为数组
// 属性 firends 类型为对象 {name: 'zs', age: 170}
App.propTypes = {
    
    
  name: PropTypes.string.isRequired,
  age: PropTypes.number,
  hobbies: PropTypes.array,
  firends: PropTypes.shape({
    
    
    name: PropTypes.string,
    age: PropTypes.number
  })
}

ReactDOM.render(
  <App name="罗小黑" age={
    
    18} hobbies={
    
    ['吃饭', '睡觉']} firends={
    
    {
    
    name:'zs', age:20}} />, 
  document.querySelector('#app')
)

默认值

调用组件时可以为组件设置默认值

如果调用组件时设置了属性值则使用属性值,没有设置属性值则使用默认属性值

import React from 'react'
import ReactDOM from 'react-dom'

class Pagination extends React.Component {
    
    
  render () {
    
    
    return (
      <div>
        每页显示数量: {
    
    this.props.pagesize}
        当前显示第{
    
    this.props.pagenum}</div>
    )
  }
}

// 设置默认值
Pagination.defaultProps = {
    
    
  pagenum: 1,
  pagesize: 10
}

ReactDOM.render(
  <Pagination pagenum={
    
    3} />, 
  document.querySelector('#app')
)

猜你喜欢

转载自blog.csdn.net/PILIpilipala/article/details/112006022