React组件-通信

99 阅读3分钟

父子组件

父传子

  • 在子组件通过属性传递内容 - 属性=值
  • 子组件通过props拿到内容 -props参数

类组件

//父级
render() {
    const { banners, productList } = this.state

    return (
      <div className='main'>
        <div>Main</div>
        <MainBanner banners={banners} title="轮播图"/>
        <MainBanner/>
        <MainProductList productList={productList}/>
      </div>
    )
  }
 //子
 //MainBanner
 export class MainBanner extends Component {
  // static defaultProps = {
  //   banners: [],
  //   title: "默认标题"
  // }

  constructor(props) {
    super(props)

    this.state = {}
  }

  render() {
    // console.log(this.props)
    const { title, banners } = this.props

    return (
      <div className='banner'>
        <h2>封装一个轮播图: {title}</h2>
        <ul>
          {
            banners.map(item => {
              return <li key={item.acm}>{item.title}</li>
            })
          }
        </ul>
      </div>
    )
  }
}
//MainProductList
export class MainProductList extends Component {
  render() {
    const { productList } = this.props

    return (
      <div>
        <h2>商品列表</h2>
        <ul>
          {
            productList.map(item => {
              return <li key={item.acm}>{item.title}</li>
            })
          }
        </ul>
      </div>
    )
  }
}

函数组件

function Child(props){
    const {name, age, height} = props
    return (
        <div>
            <p>展示父组件传递过来的数据:{ name + " " +
                age + " " + height}</p>
        </div>
    )
}
export class App extends Component {
  render() {
    return (
      <div className='app'>
           <Child name="hhh" age="18" height="18">
      </div>
    )
  }
}

子传父

  • 通过传递函数,调用回调函数
  • 通过函数的参数传递要传递的数据
//父 传递回调函数
export class App extends Component {
  constructor() {
    super()

    this.state = {
      counter: 100
    }
  }

  changeCounter(count) {
    this.setState({ counter: this.state.counter + count })
  }

  render() {
    const { counter } = this.state

    return (
      <div>
        <h2>当前计数: {counter}</h2>
        <AddCounter addClick={(count) => this.changeCounter(count)}/>
        <SubCounter subClick={(count) => this.changeCounter(count)}/>
      </div>
    )
  }
}
//子 把参数传递给回调函数
export class AddCounter extends Component {
  addCount(count) {
    this.props.addClick(count)
  }
  render() {
    return (
      <div>
        <button onClick={e => this.addCount(1)}>+1</button>
      </div>
    )
  }
}
export class SubCounter extends Component {
  subCount(count) {
    this.props.subClick(count)
  }
  render() {
    return (
      <div>
        <button onClick={e => this.subCount(-10)}>-10</button>
      </div>
    )
  }
}

参数propTypes

export class MainBanner extends Component {
  // static defaultProps = {
  //   banners: [],
  //   title: "默认标题"
  // }

  constructor(props) {
    super(props)

    this.state = {}
  }

  render() {
    const { title, banners } = this.props

    return (
      <div className='banner'>
        <h2>封装一个轮播图: {title}</h2>
        <ul>
          {
            banners.map(item => {
              return <li key={item.acm}>{item.title}</li>
            })
          }
        </ul>
      </div>
    )
  }
}

// MainBanner传入的props类型进行验证
MainBanner.propTypes = {
  banners: PropTypes.array,
  title: PropTypes.string
}

// 没有传递,默认值。MainBanner传入的props的默认值
MainBanner.defaultProps = {
  banners: [],
  title: "默认标题"
}

非父子组件的通信有哪些方式?

事件总线

Context

  • Context 提供了一种在组件之间共享此类值的方式,而不必显式地通过组件树的逐层传递 props;
  • 创建context
    • 在要使用的组件,一般是根组件导入context
    • 使用<context.Provider>包裹后代组件
    • 在要使用的后代组件引入context
      • xxxx.contextType = context
      • 在render方法中可以通过this.context拿到传递过来的值
// 1.创建一个Context
const ThemeContext = React.createContext({ color: "blue", size: 10 })

{/* 2.普通的Home */}
    {/* 第二步操作: 通过ThemeContext中Provider中value属性为后代提供数据 */}
    <UserContext.Provider value={{nickname: "kobe", age: 30}}>
      <ThemeContext.Provider value={{color: "red", size: "30"}}>
        <Home {...info}/>
      </ThemeContext.Provider>
    </UserContext.Provider>
    <Profile/>
export class HomeInfo extends Component {
  render() {
    // 4.第四步操作: 获取数据, 并且使用数据
    console.log(this.context)

    return (
      <div>
        <h2>HomeInfo: {this.context.color}</h2>
        <UserContext.Consumer>
          {
            value => {
              return <h2>Info User: {value.nickname}</h2>
            }
          }
        </UserContext.Consumer>
      </div>
    )
  }
}

// 3.第三步操作: 设置组件的contextType为某一个Context
HomeInfo.contextType = ThemeContext
    
  • Context相关API
    • React.createContext
      • 创建一个需要共享的Context对象:
      • 如果一个组件订阅了Context,那么这个组件会从离自身最近的那个匹配的 Provider 中读取到当前的context值;
      • defaultValue是组件在顶层查找过程中没有找到对应的Provider,那么就使用默认值

image.png

  • Context.Provider
    • 每个 Context 对象都会返回一个 Provider React 组件,它允许消费组件订阅 context 的变化:
    • Provider 接收一个 value 属性,传递给消费组件;
    • 一个 Provider 可以和多个消费组件有对应关系;
    • 多个 Provider 也可以嵌套使用,里层的会覆盖外层的数据;
    • 当 Provider 的 value 值发生变化时,它内部的所有消费组件都会重新渲染;

image.png

  • Class.contextType
    • 挂载在 class 上的 contextType 属性会被重赋值为一个由 React.createContext() 创建的 Context 对象:
    • 这能让你使用 this.context 来消费最近 Context 上的那个值;
    • 你可以在任何生命周期中访问到它,包括 render 函数中;

image.png

  • Context.Consumer
    • 这里,React 组件也可以订阅到 context 变更。这能让你在 函数式组件 中完成订阅 context。
    • 这里需要 函数作为子元素(function as child)这种做法;
    • 这个函数接收当前的 context 值,返回一个 React 节点;
    • 使用时机:
      1. 当使用value的组件是一个函数式组件时;
      2. 当组件中需要使用多个Context时;

image.png