其他分享
首页 > 其他分享> > React学习笔记(四)--- 组件通讯

React学习笔记(四)--- 组件通讯

作者:互联网

一、组件通讯概念

​ 在React中,组件是独立且封闭的单元,在默认情况下,组件state中的数据是私有数据,组件只能使用自身的数据。但是在实际项目开发过程中,我们的页面是由多个组件共同组成的,而这些组件之间不可避免的要共享某些数据,这个在组件之间传递数据的过程,就称为组件通讯。

二、props 基础

​ 在React中封闭的组件想要接收外部数据应该通过 props 来实现。props是一个只读的对象,对象内的属性值就是外部传递过来的数据,属性只能被读取,无法被修改,属于单向数据流。

​ 组件传递数据的方式就是在使用组件标签时给标签添加属性,属性名和属性值就会传递到props中,props中值的数据类型取决于传递的方式。如果是字符串类型的值,以键值对的形式即可,如果是数值型或其他数据类型就需要用 { } 包裹:

<Hello name="Tom" age={19} />

​ 组件接收数据的方式类组件和函数组件有所不同,在函数组件中,需要把props作为函数的参数,然后通过props.属性名 的形式来访问对应的接收的数据。

// 函数组件
function Hello(props) {
    console.log(props)
    return (
    	<div>接收到的name数据:{ props.name }</div>
    )
}

​ 而在类组件中,直接以 this.props.属性名 的形式来访问对应的接收的数据。但还有一点要注意:如果在类组件中写了构造函数 constructor ,并且想在构造函数中使用 props ,那就应该将 props 传递给 super() ,否则无法在构造函数中获取使用 props。

// 类组件
class Hello extends React.Component {
    constructor(props) {
        // 将props传递给父类构造函数
        super(props)
    }
    render() {
        return (
        	<div>接收到的age数据:{ this.props.age }</div>
        )
    }
}

三、组件通讯的四种方式

1、父向子传递数据

​ 将父组件state中的数据传递给子组件的过程比较简单,只需要父组件在使用子组件标签时添加属性,将数据向子组件传递。然后在子组件中通过 props 来接收相应的数据。

// 父组件传递数据
class Parent extends React.Component {
    state = { 
        name: '朱猪侠' 
    }
    render() {
        renturn (
            <!-- 通过属性的方式传递数据 -->
        	<div>传递数据给子组件:<Child name={this.state.name} age={22} /></div>
        )
    }
}
// 子组件接收数据
function Child(props) {
    console.log('子组件的props:', props)
    return (
        <!-- 通过props获取传递过来的数据 -->
    	<div>子组件,接收到父组件的数据:姓名:{props.name} 年龄:{props.age}</div>
    )
}
子组件的props:

在这里插入图片描述

2、子向父传递数据

​ 子组件想要传递数据给父组件,需要利用到回调函数,也就是在父组件中定义一个接收参数的回调函数,然后把这个函数利用属性传递给子组件,子组件通过props调用传递过来的回调函数,并把想要传递的数据作为回调函数的参数,此时父组件中的回调函数就获得了子组件传递过来的数据。

// 父组件
class Parent extends React.Component {
    state = {
        parentMsg: ''
    }
    // 提供回调函数,用来接收子组件传递过来的数据
    getChildMsg = data => {
        console.log('接收到子组件中传递过来的数据:', data)
        this.setState({
            parentMsg: data
        })
    }
    render() {
        return (
            <div className="parent">
                父组件:{this.state.parentMsg}
                {/*将回调函数传递给子组件*/}
                <Child getMsg={this.getChildMsg} />
            </div>
        )
    }
}
// 子组件
class Child extends React.Component {
    state = {
        msg: '我是子组件中的数据'
    }
    handleClick = () => {
        // 子组件调用父组件中传递过来的回调函数
        // 并把想要传递的数据作为参数
        this.props.getMsg(this.state.msg)
    }
    render() {
        return (
            <div className="child">
                子组件:
                {/*触发事件 调用回调函数*/}
                <button onClick={this.handleClick}>点我,给父组件传递数据</button>
            </div>
        )
    }
}

3、同级兄弟组件传递数据

​ 同级的兄弟组件之间如果想要传递数据,则需要先将想要传递的数据提升最近的公共父组件中,让公共父组件管理这个数据,并提供操作该数据的函数。首先要将该数据的操作函数传递到一个子组件A中,然后再将该数据传递到子组件B中。这样当子组件A通过props调用操作函数时,父组件中的数据就会被修改,子组件B中接收的数据也会跟着改变。

​ 简单来说就是:将兄弟组件中想要传递的私有数据提升到公共父组件中,变为共享数据。这样兄弟组件就都可以获得该数据。

// 父组件
class Counter extends React.Component {
    // 提供共享状态
    state = {
        count: 0
    }
    // 提供修改状态的方法
    onIncrement = () => {
        this.setState({
            count: this.state.count + 1
        })
    }
    render() {
        return (
            <div>
                {/*将数据传递到子组件1中*/}
                <Child1 count={this.state.count} />
                {/*将数据的操作方法传递到子组件2中*/}
                <Child2 onIncrement={this.onIncrement} />
            </div>
        )
    }
}
// 子组件1 展示数据
const Child1 = props => {
    return <h1>计数器:{props.count}</h1>
}
// 子组件2 修改数据
const Child2 = props => {
    return <button onClick={() => props.onIncrement()}>+1</button>
}

4、Context

​ 上面三种方式已经能够实现大部分场景的数据传递,但如果两个组件之间距离很远,组件嵌套很多,那此时还使用上面的数据传递方法,代码就会变的十分繁琐。所以React还提供了 Context 这一传递数据的方式,来应对跨多个组件传递数据的场景。

​ Context 提供了两个组件:Provider 和 Consumer 。Provider 组件用来包裹向外传递数据副组件的JSX结构,作为父节点,并通过 value 存储要传递的数据。Consumer 组件用来包裹想要接收使用数据的JSX结构,作为子节点,并通过回调函数的参数来使用存储的数据。

// 1.创建context  并得到Provider 和 Consumer两个组件
const { Provider, Consumer } = React.createContext()

class App extends React.Component {
  render() {
    return (
        //  包裹JSX结构,并通过 value 属性存储想要传递的数据
      <Provider value="pink">
        <div className="app">
          <Node />
        </div>
      </Provider>
    )
  }
}

const Node = props => {
  return (
    <div className="node">
      <SubNode />
    </div>
  )
}

const SubNode = props => {
  return (
    <div className="subnode">
      <Child />
    </div>
  )
}

const Child = props => {
  return (
    <div className="child">
          {/* 通过函数的参数,使用Provider存储的数据 */}
      <Consumer>{data => <span>我是子节点 -- {data}</span>}</Consumer>
    </div>
  )
}

ReactDOM.render(<App />, document.getElementById('root'))

四、props 深入

1、children 属性

​ 在组件中我们可以通过 props 的 children 属性来获取当前组件标签内的子节点,子节点可以是文本、React元素、组件以及函数等。

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

// children 为 函数
const App = props => {
  console.log(props)
  props.children()

  return (
    <div>
      <h1>组件标签的子节点:</h1>
      {/* {props.children} */}
    </div>
  )
}

ReactDOM.render(
  <App>{() => console.log('这是一个函数子节点')}</App>,
  document.getElementById('root')
)

2、校验 props 的数据类型

​ 对于组件本身来说,props 是由使用者传递过来的,数据类型和格式由使用者决定。但在实际开发中,我们通常只希望使用者传递我们所规定的数据类型。所以react提供了一个名为 prop-types 的依赖包,可以让我们指定传递给组件的数据格式,而且如果传递的数据不符合指定的数据格式,还会在控制台给出明确的错误提示。

在项目中使用 prop-types 的步骤:

​ ① 安装依赖包 npm install props-types 或 yarn add prop-types

​ ② 导入下载的依赖包

​ ③ 通过 组件名.proptypes = { prop名称: PropTypes.数据类型 } 来给组件的props指定数据类型

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

const App = props => {
  const arr = props.colors
  const lis = arr.map((item, index) => <li key={index}>{item}</li>)
  return <ul>{lis}</ul>
}

// 添加props校验
App.propTypes = {
  colors: PropTypes.array
}

ReactDOM.render(
  <App colors={['red', 'blue']} />,
  document.getElementById('root')
)
常见的prop约束规则:

​ ① 常见数据类型:array、bool(即boolean)、func(即function)、number、object、string 等

​ ② React元素类型:element

​ ③ 必填验证:isRequired,即要求props中必须有该数据。

​ ④ 特定结构的对象:shape({ }) ,即对 对象中的 某些属性的数据类型,做出约束。

注意: 当想要同时使用多条验证规则时,只需要采用链式编程的方式即可,如 PropTypes.func.isRequired ,要求既是函数又是必填项。

import PropTypes from 'prop-types'

const App = props => {
  return (
    <div>
      <h1>props校验:</h1>
    </div>
  )
}
// 添加props校验
// 属性 a 的类型:      数值(number)
// 属性 fn 的类型:     函数(func)并且为必填项
// 属性 tag 的类型:    React元素(element)
// 属性 filter 的类型: 对象({area: '上海', price: 1999})
App.propTypes = {
  a: PropTypes.number,
  fn: PropTypes.func.isRequired,
  tag: PropTypes.element,
  filter: PropTypes.shape({
    area: PropTypes.string,
    price: PropTypes.number
  })
}

ReactDOM.render(<App fn={() => {}} />, document.getElementById('root'))

3、prop 默认值

​ 我们可以给组件的某些prop,设置默认值,当组件在使用时,没有传入该prop数据,那我么那就使用默认值来设置组件。设置默认值需要借助于组件的 defaultProps 属性:

const App = props => {
    return (
        <div>
            <h1>props校验:{ props.a }</h1>
        </div>
    )
}

App.defaultProps = {
    a: 123  // 给props中的 a 设置默认值
}
ReactDOM.render(<App />, document.getElementById('root'))

标签:React,return,---,传递,props,组件,数据,传递数据
来源: https://blog.csdn.net/weixin_45092437/article/details/122631599