问题:当一个子组件修改了全局变量,并没有通知其他组件时,其他组件不知道这个值改变了
http://js.jirengu.com/lipadokebu/2/edit?html,js,output
image.png
声明eventHub
eventHub作为事件中心,实现订阅发布功能

  1. let fnLists = {}
  2. let eventHub = {
  3. trigger(eventName, data){
  4. let fnList = fnLists[eventName]
  5. if(!fnList) return
  6. for(let i=0; i < fnList.length; i++){
  7. fnList[i](data)
  8. }
  9. },
  10. on(eventName, fn){
  11. if(!fnLists[eventName]){
  12. fnLists[eventName] = []
  13. }
  14. fnLists[eventName].push(fn)
  15. }
  16. }

声明一个管家,init初始化,先把”我要花钱”事件名和对应的函数fn插入到fnLists

  1. let x = {
  2. init(){
  3. // 先把事件名和函数插入fnLists
  4. eventHub.on('我要花钱', function(data){
  5. money.amount -= data
  6. render()
  7. })
  8. }
  9. }
  10. x.init()

只有根组件知道money, 并通过props传给其他组件

  1. class App extends React.Component {
  2. constructor(){
  3. super()
  4. this.state = {
  5. money: money
  6. }
  7. }
  8. render(){
  9. return (
  10. <div className="root">
  11. <Bigpa money={this.state.money}/>
  12. <Secpa money={this.state.money}/>
  13. </div>
  14. )
  15. }
  16. }
  17. class Bigpa extends React.Component {
  18. constructor(){
  19. super()
  20. }
  21. render(){
  22. return (
  23. <div className="papa">Bigpa {this.props.money.amount}
  24. <Son1 money={this.props.money}/>
  25. <Son2 money={this.props.money}/>
  26. </div>
  27. )
  28. }
  29. }
  30. class Son2 extends React.Component {
  31. constructor(){
  32. super()
  33. }
  34. comsume(){
  35. eventHub.trigger('我要花钱', 100) // 触发事件
  36. }
  37. render(){
  38. return (
  39. <div className="son">Son2 {this.props.money.amount}
  40. <button onClick={()=>this.comsume()}>消费</button>
  41. </div>
  42. )
  43. }
  44. }

当子组件eventHub.trigger('我要花钱', 100) 时,就会调用fnLists里对应的函数,更新money的值,
调用render()渲染到页面(React只会更新变化了的部分)

http://js.jirengu.com/lipadokebu/3/edit?html,js,output

引入Redux, Redux 是 JavaScript 状态容器,提供可预测化的状态管理。
概念:
store存储所有数据

  1. let money = {
  2. amount: 100000
  3. }
  4. let user = {
  5. id: 123232,
  6. nickname: '土豪'
  7. }
  8. let store = {
  9. money: money,
  10. user: user
  11. }

eventHub.trigger是action
第一个参数是action type, 第二个参数是payload

  1. // action
  2. eventHub.trigger('我要花钱' /*action type*/, 100 /*payload*/)

eventHub.on是subscribe
on里数据操作是reducer

  1. eventHub.on('我要花钱', function(data){ // subscribe
  2. money.amount -= data // reducer
  3. render()
  4. })

看官方实例学习
使用Redux创建store

  1. let createStore = Redux.createStore
  2. let reducers = (state, action) => {
  3. state = state || {
  4. money: {amount: 100000}
  5. }
  6. switch (action.type) {
  7. case '我要花钱':
  8. return {
  9. money: {
  10. amount: state.money.amount - action.payload
  11. }
  12. }
  13. default:
  14. return state
  15. }
  16. }
  17. const store = createStore(reducers)
  18. console.log(store.getState())

dispatch触发action

  1. comsume(){
  2. // eventHub.trigger('我要花钱', 100)
  3. store.dispatch({type: '我要花钱', payload: 100})
  4. }

subscribe并render

  1. function render(){
  2. ReactDOM.render(<App store={store.getState()}/>, document.querySelector("#root"))
  3. }
  4. render()
  5. store.subscribe(()=>render())

注意数据改用props传给App
http://js.jirengu.com/qabefirulo/1/edit?html,js,output

Redux的意义
事件名自定义,在reducers里列好
state是只读的,没办法用App里的state,但也没办法阻止组件修改根数据(JS毛病)
阻止猪队友

总结:组件之间如何通信?

1. 使用 eventHub/eventBus 来通信

一个组件监听某个事件,另一个组件触发相同的事件并传参,即可实现两个组件的通信
缺点是事件容易越来越多,不好控制代码的复杂度

2. 使用 Redux

每次操作触发一个 action
action 会触发对应的 reducer
reducer 会用旧的 state 和 action 造出一个新的 state
使用 store.subscribe 监听 state 的变化,一旦 state 变化就重新 render(render 会做 DOM diff,确保只更新该更新的 DOM)