目录
目录
1.props传值:父传子使用props;子组件向父组件传值通过回调函数
2.多层嵌套组件通信:使用context共享组件树中的数据(生产者消费者模式)
3. 非嵌套组件(兄弟)之间的通信:基于消息订阅-发布者模式
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'));