React 之组件通讯

一、组件通讯介绍

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

二、组件的props

1、props的作用 :用于接收外界向组件中传递的数据

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

  • 函数组件通过 参数props 接收数据
  • 类组件通过 this.props 接收数据

2、props的特点:

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

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

import React from 'react'
import ReactDOM from 'react-dom'
//通过props来接收数据
const Hello = (props)=>{
  //props是一个对象
  console.log(props);
  return(
    <div>
      <h1>我的名字是:{props.name}</h1>
    </div>
  )
}
//传递数据
ReactDOM.render(<Hello name='jack' />, document.getElementById('root'))      

在这里插入图片描述
4、类组件中接收自定义属性中的数据

类组件方式1

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

class Hello extends React.Component{
  render(){
    console.log(this.props);   //this.props是存储数据的对象
    return(
      <div>
        <h1>我的名字是:{this.props.name},今年{this.props.age}岁了</h1>
      </div>
    )
  }
}
//传递数据
ReactDOM.render(<Hello name='anni' age={19}/>, document.getElementById('root'))      

调用组件时,使用自定义属性将数据传递到组件内部
this.props.name this,props.age
在这里插入图片描述
类组件方式2

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

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

class Hello extends React.Component{
  constructor(props){
    super(props)
  }

  render(){
    return(
      <div>
        <h1>我的名字是:{this.props.name},今年{this.props.age}岁了</h1>
      </div>
    )
  }
}
//传递数据
ReactDOM.render(<Hello name='anni' age={19}/>, document.getElementById('root'))      

三、组件通讯的三种方式

1、父组件传递数据给子组件

实现要点:

  • 父组件提供state,并且内部设置好传递给子组件的数据
  • 父组件调用子组件时,为组件标签添加自定义属性,值为 state 中的数据
  • 子组件中通过 props 接收父组件中传递的数据
import React from 'react'
import ReactDOM from 'react-dom'
import './css/b.css'
// 目标: 子组件接收到父组件的数据
class Father extends React.Component {
  state = {
    name: 'anni',
    age: 18
  }
  render () {
    return (
      <div className="father" class="father">
        我是父组件
        {/* 父组件在调用子组件时,将数据通过自定义属性传递给子组件 */}
        <Son name={this.state.name} age={this.state.age} />
      </div>
    )
  }
}

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

在这里插入图片描述

2、子组件传递数据给父组件

核心: 利用回调函数

父组件

  • 父组件提供一个回调函数用于接收子组件的数据
  • 父组件调用子组件时,将函数作为参数传给子组件

子组件 (子组件已经将父组件函数保存在 props 中)

  • 子组件中使用 state 定义要传递给父组件的数据
  • 子组件利用事件调用父组件传递的函数,并将数组作为参数传入
import React from 'react'
import ReactDOM from 'react-dom'
import './css/b.css'

// 目标: 将子组件中的数据传递到父组件中
class Father extends React.Component {
  //提供回调函数,用来接收数据
  getChildData = (data) =>{
    console.log("getChildData:",data)
  }
  render () {
    return (
      <div className="father">
        <div>我是父组件</div>
        <Son name="zs" age={18} fn={this.getChildData}/>
      </div>
    )
  }
}

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="son">
        <div>我是子组件</div>
        <button onClick={this.handleClick}>发送</button>
      </div>
    )
  }
}

//传递数据
ReactDOM.render(<Father/>, document.getElementById('root'))      

在这里插入图片描述

3、兄弟组件传值

思路: 状态提升

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

  • 子组件1 通过调用父组件的函数将数据传递给父组件 (子向父传值)
  • 父组件再通过子组件属性向子组件2传值 (父向子传值)
import React from 'react'
import ReactDOM from 'react-dom'
import './css/b.css'


class App extends React.Component {
  //提供共享状态
  state = {
    count:0
  }
  //提供修改状态的方法
  onIncrement = ()=>{
    this.setState({
      count:this.state.count + 1
    })
  }
  render () {
    return (
        <div>
         
          <Child1 count={this.state.count}/>
          <Child2 onIncrement = {this.onIncrement}/>
        </div>
    )
  }
}


const Child1 = props => {
  return <h1>计数器:{props.count}</h1>
}

const Child2 = () => {
  return <button onClick = {()=>{this.onIncrement()}}>+1</button>
}
//传递数据
ReactDOM.render(<App/>, document.getElementById('root'))      

4、Context

传统方式缺陷明显,一层一层传递太过复杂,使用 Context 便可以实现跨组件传值(比如主题,语言等)

实现步骤:

  • 调用 React.createContext() 方法创建 Provider (提供数据) 和 Consumer (消费数据)
  • 使用 Provider 组件作为父节点,并使用 value属性传递数据
  • 使用 Consumer 接收数据
import React from 'react'
import ReactDOM from 'react-dom'
import './css/b.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.getElementById('root'))      

效果如图:实现了跨层传输数据
在这里插入图片描述

四、props 深入

1、children 属性

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

//children为JSX
const Test = ()=> <button>我是button组件</button>
//children为文本
const App = props =>{
  console.log(props);
  props.children()
  return(
    <div>
      <h1>组件标签的子节点:</h1>
      {props.children}
    </div>
  )
}
ReactDOM.render(<App>
  {/* <p>我是一个子节点,是一个p标签</p>
  <Test/> */}
  {/* 函数子节点 */}
  {
    ()=> console.log('这是一个函数子节点')
  }
</App>, document.getElementById('root'))      

2、props 校验

props用来接收外来数据,这些数据可以在组件中被使用,但是组件的调用者可能会传入一些不符合规则的数据,当组件调用者传入不符合规则的数据时,通过props 校验进行错误提示从而更快找到问题。

props 校验:是允许在创建组件的时候,就指定 props 的类型、格式在用户调用组件出现错误时产生的原因。

使用步骤:

	 1. 安装 prop-types: npm i prop-types
	 2. 导入 prop-types 包
	 3. 为组件添加propTypes验证
//1. 导入 prop-types 包
import PropTypes from 'prop-types'

//2. 使用组件名.propTypes = {}来为组件的props添加校验规则,校验规则由PropTypes对象来指定
App.propTypes = {
   color: PropTypes.array
}

3、常见校验规则

  • 常见数据类型: array、bool、func、number、object、string
  • React元素类型: element(props.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>
    
    )
  }
}

// 属性 a 类型为数值
// 属性 fn  类型为函数
// 属性 tag 类型为元素
// 属性 firends 类型为 对象 {name: 'anni', age: 18}
App.propTypes = {
  a: PropTypes.number,
  fn: PropTypes.func.isRequired,
  sum: PropTypes.number,
  firends: PropTypes.shape({
    name: PropTypes.string,
    age: PropTypes.number
  })
}

ReactDOM.render(
  <App a={18} fn={()=>{}} sum={1+2} firends={{name:'anni', age:18}} />, 
  document.getElementById('root')
)

4、Props默认值

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

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

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

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

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

ReactDOM.render(
  <Pagination pagenum={3} />, 
  document.getElementById('root')
)
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
React Umi 中,可以使用以下几种方式进行跨组件通讯: 1. 属性传递 在父组件中定义一个 state 或者 props,然后通过 props 将数据传递给子组件。 2. Context Context 是一种在组件树中共享数据的方式,它可以避免通过 props 层层传递数据的繁琐。 使用 Context 的步骤如下: 1)创建一个 Context 对象 ```jsx const MyContext = React.createContext(defaultValue); ``` 2)在父组件中使用 Provider 提供数据 ```jsx <MyContext.Provider value={value}> <ChildComponent /> </MyContext.Provider> ``` 3)在子组件中使用 Consumer 获取数据 ```jsx <MyContext.Consumer> {value => /* 根据 value 渲染子组件 */} </MyContext.Consumer> ``` 3. Redux Redux 是一种状态管理库,它可以让应用中的所有组件共享一个数据源。通过在组件中 dispatch action 来改变应用状态,并通过 connect 方法将组件与 Redux 连接起来。 使用 Redux 的步骤如下: 1) 创建一个 store 对象 ```js import { createStore } from 'redux'; const reducer = (state, action) => { // 根据 action 更新 state }; const store = createStore(reducer, initialState); ``` 2) 在组件中 dispatch action 来更新应用状态 ```js import { connect } from 'react-redux'; import { updateState } from './actions'; const MyComponent = ({ state, updateState }) => { const handleClick = () => { updateState(newState); }; return <button onClick={handleClick}>{state}</button>; }; const mapStateToProps = state => ({ state }); const mapDispatchToProps = { updateState }; export default connect(mapStateToProps, mapDispatchToProps)(MyComponent); ``` 其中,updateState 是一个 action creator,它返回一个 action 对象,用于更新应用状态。 4. EventBus EventBus 是一种基于事件的通讯方式,它可以让任意组件之间相互通讯。 使用 EventBus 的步骤如下: 1)创建一个 EventBus 对象 ```js const eventBus = new EventEmitter(); ``` 2)在发送事件的组件中 emit 事件 ```js eventBus.emit('eventName', eventData); ``` 3)在接收事件的组件中监听事件 ```js componentDidMount() { eventBus.on('eventName', this.handleEvent); } componentWillUnmount() { eventBus.off('eventName', this.handleEvent); } handleEvent = eventData => { // 处理事件 }; ``` 以上是 React Umi 中跨组件通讯的几种方式。根据实际情况选择合适的方式进行通讯

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值