首先先给出原生js的发布订阅模式:
发布订阅模式也称为观察者模式
简单版本:
//调度中心
let bus = {
list: [],
subscribe(cb) {
this.list.push(cb);
},
publish(val) {
this.list.forEach(cb => {
cb && cb(val);
})
}
}
//订阅
bus.subscribe((val) => {
console.log(111, val); //111,333
})
bus.subscribe((val) => {
console.log(222, val); //222,333
})
//发布
setTimeout(() => {
bus.publish(333)
}, 0);
稍全面点的版本:
class EventEmitter {
constructor() {
this.bus = {};
}
subscribe(eventName, callback) {
if(!this.bus[eventName]) this.bus[eventName] = [];
this.bus[eventName].push(callback);
return {
unsubscribe: () => {
this.bus[eventName] = this.bus[eventName].filter(item => item !== callback);
}
};
}
emit(eventName, args = []) {
let cbArr = this.bus[eventName];
if(!cbArr) return [];
return cbArr.map(cb => cb(...args));
}
}
/**
* const emitter = new EventEmitter();
*
* // Subscribe to the onClick event with onClickCallback
* function onClickCallback() { return 99 }
* const sub = emitter.subscribe('onClick', onClickCallback);
*
* emitter.emit('onClick'); // [99]
* sub.unsubscribe(); // undefined
* emitter.emit('onClick'); // []
*/
那么react中调用发布订阅模式也是同理(包括常用的数据管理工具redux的原理也是基于该模式)
export default class App extends Component {
state = {
filmList : []
}
constructor() {
super()
axios.get(`/test.json`).then(res => {
this.setState({
filmList: res.data.data.films
})
})
}
render() {
return (
<div>
{
// 电影列表组件
this.state.filmList.map(item =>
<FilmItem key={item.filmId} {...item}></FilmItem>
)
}
{/* 电影详细信息组件 */}
<FilmDetail></FilmDetail>
</div>
)
}
}
class FilmItem extends Component {
render() {
let { name, poster, synopsis } = this.props
return (
// 发布者 将电影详细信息作为参数传给订阅者的回调函数
<div className='filmItem' onClick={() => {
bus.publish(synopsis)
}}>
<img src={poster} alt={name} />
<h4>{name}</h4>
</div>
)
}
}
class FilmDetail extends Component {
// 将接收到的信息存到状态里才能被渲染到页面上
state = {
info: ''
}
// 将订阅函数写在constructor里 使得组件被初始化时就执行订阅
constructor() {
super();
// 将发布者传过来的信息设置成新的state
bus.subscribe((info) => {
this.setState({
info: info
})
})
}
render() {
return (
<div className='filmDetail'>
{this.state.info}
</div>
)
}
}
//调度中心
let bus = {
list: [],
subscribe(cb) {
this.list.push(cb);
},
publish(val) {
this.list.forEach(cb => {
cb && cb(val);
})
}
}