第十一节-Context与组合的应用场景和使用问题

169 阅读2分钟

Context 给整个组件树共享全局数据的

有全局,就一定会出现污染和复用性的问题

  • 简单城市选择器的例子
import React, { Component } from 'react'

const CityContext = React.createContext({
  name: 'lingling',
  text: '零陵'
})

class Select extends Component {
  /**
   * 将上下文的类型指定为 CityContext
   * this.context -> this.state.cityInfo
   * 向上找最近的CityContext的Provider,并且取值 cityInfo
   */
  static contextType = CityContext//但是这种东西其实是对组件进行污染了
  render() {
    return (
      <select
        value={this.context.name}
        onChange={(e) => this.props.changeCity({
          name: e.target.value,
          text: e.target[e.target.selectedIndex].text//获取的内容
        })}
      >
        <option value="beijing">北京</option>
        <option value="chengdu">成都</option>
        <option value="shenzhen">深圳</option>
        <option value="lingling">零陵</option>
      </select>
    )
  }
}
class Header extends Component {
  render() {
    return (
      <Select changeCity={this.props.changeCity} />
    )
  }
}

export default class App extends Component {
  state = {
    cityInfo: {
      name: 'lingling',
      text: '零陵'
    }
  }
  changeCity(cityInfo) {
    this.setState({ cityInfo })
  }
  render() {
    return (
      <CityContext.Provider value={this.state.cityInfo}>
        <Header changeCity={this.changeCity.bind(this)} />
        <span>{this.state.cityInfo.text}</span>
      </CityContext.Provider>
    )
  }
}

image.png

总结

  • 最适合的场景:杂乱无章的组件都需要同一些数据的时候,层级过多的时候
  • 单纯为了不层层传递属性,Context 实际上是不合适(组件是要有纯度的,复用性不好)
  • Context的弱点: 弱化及污染组件的纯度,度导致组件的复用性降低
    • 上述的 Select组件如果只做城市选择的话,static contextType = CityContext就没啥问题
    • 但是如果是通用的选择器的话,就不行了

思考并处理上述的问题

  • 通过组合组件的方式来处理,就不用一层层搞了
    • 就是通过把组件当作属性传给子元素
    • 这种的方式更加清晰,不需要和上面的Header组件中再去传递一次prop,可以直接给App来做的
import React, { Component } from 'react'

class Selector extends Component {

  render() {
    return (
      <select
        defaultValue={this.props.cityInfo.name}
        onChange={(e) => this.props.changeCity({
          name: e.target.value,
          text: e.target[e.target.selectedIndex].text//获取的内容
        })}
      >
        {
          this.props.cityData.map((item, index) => {
            return <option value={item.value} key={index}>{ item.text }</option>
          })
        }  
      </select>
    )
  }
}

class Header extends Component {
  render() {
    return (
      <header>
        <h1>{this.props.text}</h1>
        <div>{ this.props.citySelector }</div>
      </header>
    )
  }
}

export default class App extends Component {
  state = {
    headerTitle: '标题',
    cityInfo: {
      name: 'lingling',
      text: '零陵'
    },
    cityData: [
      {name: 'beijing', text: '北京'},
      {name: 'shenzhen', text: '深圳'},
      {name: 'lingling', text: '零陵'},
    ]
  }
  changeCity(cityInfo) {
    this.setState({
      cityInfo
    })
  }
  render() {
    return (
      <>
        <Header
          text={this.state.headerTitle}
          citySelector={
            <Selector
              cityData={this.state.cityData}
              cityInfo={this.state.cityInfo}
              changeCity={this.changeCity.bind(this)}
            ></Selector>
          }
        ></Header>
        <span>{ this.state.cityInfo.text }</span>
      </>
    )
  }
}

image.png

结论

  • react的组件尽量扁平化层级不要太深,会方便对数据的传递
  • Context使用适可而止看场景使用吧