react中组件通信总结

目录

目录

1.props传值:父传子使用props;子组件向父组件传值通过回调函数

2.多层嵌套组件通信:使用context共享组件树中的数据(生产者消费者模式)

3. 非嵌套组件(兄弟)之间的通信:基于消息订阅-发布者模式 

4.非嵌套组件(兄弟)之间的通信:events包的使用

5.集中式管理:使用redux 

1.props传值:父传子使用props;子组件向父组件传值通过回调函数

2.多层嵌套组件通信:使用context共享组件树中的数据(生产者消费者模式)

(1) 创建一个context对象:

const MyContext = React.createContext(defaultValue);

只有当组件所处的树中没有匹配到 Provider 时,其 defaultValue 参数才会生效

每个 Context 对象都会返回一个 Provider React 组件,它允许消费组件订阅 context 的变化。

(2)在嵌套组件中更新 Context

父组件:

  render() {
    return (
      <div>
        <ThemeContext.Provider value={this.state}>
          ......
        </ThemeContext.Provider>
        <div>
        </div>
      </div>
    );
  }

 在子组件中使用context

// 方法1:挂载在 class 上的 contextType 属性赋值为声明的context
class ThemedButton extends React.Component {
  render() {
    let props = this.props;
    let {theme} = this.context;
    return (
      <button {...props} style={{backgroundColor: theme.background}}>test</button>
    );
  }

  static contextType = ThemeContext
}
// 方法2:使用Context.Consumer
// 这个函数接收当前的 context 值,返回一个 React 节点。传递给函数的 value 值等同于往上组件树
// 离这个 context 最近的 Provider 提供的 value 值。如果没有对应的 Provider,value 参数等同
// 于传递给 createContext() 的 defaultValue。
<MyContext.Consumer>
  {value => /* 基于 context 值进行渲染*/}
</MyContext.Consumer>

 来个demo验证一下

  const themes = {
  light: {
    foreground: '#000000',
    background: '#eeeeee',
  },
  dark: {
    foreground: '#000',
    background: '#634',
  },
};

// const ThemeContext = React.createContext(
//  themes.dark, // 默认值
// );
const ThemeContext = React.createContext();

class ThemedButton extends React.Component {
  render() {
    let props = this.props;
    let {theme} = this.context;
    return (
      <button {...props} style={{backgroundColor: theme.background}}>test</button>
    );
  }

  static contextType = ThemeContext
}

function ThemeTogglerButton() {
  // Theme Toggler 按钮不仅仅只获取 theme 值,它也从 context 中获取到一个 toggleTheme 函数
  return (
    <ThemeContext.Consumer>
      {({theme, toggleTheme}) => {
        return <button onClick={toggleTheme} style={{backgroundColor: theme.background}}>
          Toggle Theme
        </button>
      }
      }
    </ThemeContext.Consumer>
  );
}

class App extends React.Component {
  constructor(props) {
    super(props);

    // State 也包含了更新函数,因此它会被传递进 context provider。
    this.state = {
      theme: themes.light,
      toggleTheme: this.toggleTheme,
    };
  }
  toggleTheme = () => {
      this.setState(state => ({
        theme: state.theme === themes.dark ? themes.light : themes.dark,
      }));
    };

  render() {
    // 在 ThemeProvider 内部的 ThemedButton 按钮组件使用 state 中的 theme 值,
    // 而外部的组件使用默认的 theme 值
    return (
      <div>
        <ThemeContext.Provider value={this.state}>
          <ThemedButton onClick={this.toggleTheme}/>
          <ThemeTogglerButton />
        </ThemeContext.Provider>
        <div>
        </div>
      </div>
    );
  }
}

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

16.3之前

(1) 在父组件中定义childContextTypes,用来声明向后代组件传递的;

(2)在父组件中定义getChildContext方法(固定写法,不可修改方法名);

(3)在子组件中定义static contextTypes

3. 非嵌套组件(兄弟)之间的通信:基于消息订阅-发布者模式 

 这种方式需要安装pubsub-js插件,实现消息的发布和订阅,应用场景是兄弟组件之间传值。执行以下命令安装插件

npm install pubsub.js 

import PubSub from 'pubsub-js'
class A extends React.Component {
  state = {
    car: '特斯拉'
  }
  publishMessage = () => {
    console.log('publish')
    PubSub.publish('car', this.state.car);
  }
  render () {
    return <button onClick={this.publishMessage}>点击给兄弟组件传汽车的名字</button>
  }
}

class B extends React.Component {
  state = {
    car: '奥迪'
  }
  componentDidMount () {
    // 当组件初始化时开始监听订阅,出现类型为car的消息,立马调用回调函数mySubscriber
    this.sub = PubSub.subscribe('car', this.mySubscriber)
  }
  mySubscriber = (msg, data) => {
    console.log('subscribe')
    this.setState({car: data})
  }
  componentWillUnmount () {
    // 当组件销毁时,取消订阅
    PubSub.unsubscribe(this.sub)
  }
  render () {
    return <div>我现在的车是{this.state.car}</div>
  }
}
class Main extends React.Component {
 render () {
   return (
     <div>
      <A/>
      <B/>
      </div>
   )
 }
}

ReactDOM.render(
  <React.StrictMode>
    <Main />
  </React.StrictMode>,
  document.getElementById('root')
);

4.非嵌套组件(兄弟)之间的通信:events包的使用

(1)npm install events --save  

(2)引入 events 包,并向外提供一个事件对象,供通信时使用

import {EventEmitter} from 'events'
const emitter = new EventEmitter()
class C extends React.Component {
    myColor = () => {
      emitter.emit('changeColor', 'red')
    }

    render () {
      return <div>
        <span>组件C</span>
        <button onClick={this.myColor}>告诉D我选择的颜色</button>
      </div>
    }
}
class D extends React.Component {
  state = {
    color: ''
  }
  componentDidMount () {
    let _this = this
    this.eventEmitter = emitter.on('changeColor', function (data) {
      _this.setState({color: data})
    })
  }

  componentWillUnmount () {
    emitter.removeListener(this.eventEmitter)
  }
 
  render () {
    return <div>
      <span>组件D:接收到的颜色是{this.state.color}</span>
    </div>
  }
}
class Main extends React.Component {
 render () {
   return (
     <div>
      <C/>
      <D/>
      </div>
   )
 }
}

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

5.集中式管理:使用redux 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值