react通信方式梳理

| 导语 梳理父组件向子组件、子组件向父组件、跨级组件间、非嵌套组件间通信方式以及如何用redux进行数据管理

1、父组件向子组件通信

1)传递props

最常见的组件通信方式,一般父组件通过props向子组件传送数据
父组件App.js

import React, { Component } from "react";
import { render } from "react-dom";
import Sub from "./sub";

class App extends Component {
  render() {
    return <Sub title="hello, react" />;
  }
}

render(<App />, document.getElementById("root"));

子组件Sub.js

import React from "react";

const Sub = props => {
  return <h1>{props.title}</h1>;
};

export default Sub;

2)调用子组件方法

父组件直接调用子组件的方法,也可以达到通信的目的
父组件App.js

import React, { Component } from "react";
import { render } from "react-dom";
import Sub from "./sub";

class App extends Component {
  hideSub() {
    this.refs.subComponent.hide();
  }

  render() {
    return (
      <div>
        <Sub ref="subComponent" />
        <button onClick={this.hideSub.bind(this)}>隐藏子组件</button>
      </div>
    );
  }
}

render(<App />, document.getElementById("root"));

子组件Sub.js

import React, { Component } from "react";

export default class Sub extends Component {
  state = {
    show: true
  };

  hide() {
    this.setState({
      show: false
    });
  }

  render() {
    return this.state.show ? <h1>hello, react</h1> : null;
  }
}

2、子组件向父组件通信

1)回调父组件通过props传递过来的方法

父组件App.js

import React, { Component } from "react";
import { render } from "react-dom";
import Sub from "./sub";

class App extends Component {
  state = {
    showSubComponent: true
  };

  showSub() {
    this.setState({
      showSubComponent: true
    });
  }

  hideSub() {
    this.setState({
      showSubComponent: false
    });
  }

  render() {
    return (
      <div>
          {
              this.state.showSubComponent 
              ? <Sub ref="subComponent" hideSub={this.hideSub.bind(this)} /> 
              : null
          }

          <button onClick={this.showSub.bind(this)}>显示子组件</button>
      </div>
    );
  }
}

render(<App />, document.getElementById("root"));

子组件Sub.js

import React, { Component } from "react";

export default class Sub extends Component {
  render() {
    let { hideSub } = this.props;
    return (
      <div>
        hi,react <button onClick={() => hideSub()}>隐藏</button>
      </div>
    );
  }
}

2)自定义事件

event.js

import { EventEmitter } from "events";
export default new EventEmitter();

父组件App.js

import React, { Component } from "react";
import { render } from "react-dom";
import emitter from "./event";
import Sub from "./sub";

const list = ["apple", "banana"];

class App extends Component {
  state = {
    msg: ""
  };

  componentDidMount() {
    // 声明自定义事件
    this.eventEmitter = emitter.on("subClick", msg => {
      this.setState({
        msg
      });
    });
  }

  render() {
    return (
      <div>
        {this.state.msg}
        <ul>
          {list.map((item, index) => (
            <Sub key={index} name={item} />
          ))}
        </ul>
      </div>
    );
  }
}

render(<App />, document.getElementById("root"));

子组件Sub.js

import React, { Component } from "react";
import emitter from "./event";

export default class Sub extends Component {
  handleClick() {
    emitter.emit("subClick", this.props.name);
  }

  render() {
    return <li onClick={this.handleClick.bind(this)}>{this.props.name}</li>;
  }
}

3、跨级组件间通信

1)通过props层层传递,中间的组件也需要添加对应的props属性,传递给下一层

import React, { Component } from "react";
import { render } from "react-dom";

const ThemeButton = props => <button style={{color: props.theme}}>{props.theme}</button>

// 中间组件,将theme传递给ThemeButton
const Toolbar = props => <ThemeButton theme={props.theme}/>

class App extends Component {
  render() {
    return <Toolbar theme="red"/>;
  }
}

render(<App />, document.getElementById("root"));

2)使用context

import React, { Component } from "react";
import { render } from "react-dom";

// 创建一个theme context,默认值为light
const { Provider, Consumer } = React.createContext("light");

const ThemeButton = props => {
  return <Consumer>{theme => <button {...props}>{theme}</button>}</Consumer>;
};

// 中间组件
const Toolbar = props => <ThemeButton />;

class App extends Component {
  render() {
    return (
      <Provider value="dark">
        <Toolbar />
      </Provider>
    );
  }
}

render(<App />, document.getElementById("root"));

4、非嵌套组件间通信

就是没有包含关系的组件,比如兄弟组件
1)自定义事件
父组件App.js

import React, { Component } from "react";
import { render } from "react-dom";
import Sub from "./sub";
import Sub2 from "./sub2";

class App extends Component {
  render() {
    return (
      <div>
        <Sub />
        <Sub2 />
      </div>
    );
  }
}

render(<App />, document.getElementById("root"));

子组件Sub.js

import React, { Component } from "react";
import emitter from "./event";

export default class Sub extends Component {
  handleClick() {
    emitter.emit("siblingsMsg", "组件一");
  }

  render() {
    return (
      <div>我是组件一:<button onClick={this.handleClick.bind(this)}>点我点我</button></div>
    )
  }
}

子组件Sub2.js

import React, { Component } from "react";
import emitter from "./event";

export default class Sub2 extends Component {
  state = {
    msg: ''
  }

  componentDidMount() {
    // 声明自定义事件
    this.eventEmitter = emitter.on("siblingsMsg", msg => {
      this.setState({
        msg
      });
    });
  }

  render() {
    return (
        <div>我是组件二:收到来自{this.state.msg}的信息</div>
    );
  }
}

5、使用redux进行数据管理

入口文件index.js

import React, { Component } from "react";
import { render } from "react-dom";
import { createStore, applyMiddleware } from "redux";
import { Provider } from "react-redux";
import { createLogger } from "redux-logger";
import thunk from "redux-thunk";
import rootReducer from "./reducers";
import App from "./components/app";

const middleware = [thunk];
if (process.env.NODE_ENV !== "production") {
  middleware.push(createLogger());
}

const store = createStore(rootReducer, applyMiddleware(...middleware));

render(
  <Provider store={store}>
    <App />
  </Provider>,
  document.getElementById("root")
);

components/app.js

import React, { Component } from "react";
import { connect } from "react-redux";
import Sub from "./sub";
import { changeList, toggleItem } from "../actions";

class App extends Component {
  componentWillMount() {
    this.props.changeList();
  }

  render() {
    const { list, toggle } = this.props;
    return (
      <ul>
        {list &&
          list.map((item, index) => (
            <Sub
              key={item.id}
              {...item}
              doClick={() => toggle(item.id)}
            />
          ))}
      </ul>
    );
  }
}

const mapStateToProps = state => ({
  list: state
});

const mapDispatchToProps = dispatch => ({
  toggle: id => dispatch(toggleItem(id)),
  changeList: () => dispatch(changeList())
});

export default connect(
  mapStateToProps,
  mapDispatchToProps
)(App);

components/sub.js

import React, { Component } from "react";

export default class Sub extends Component {
  render() {
    const { id, name, removed, doClick } = this.props;

    return (
      <li
        onClick={doClick}
        style={{ textDecoration: removed ? "line-through" : "none" }}
      >
        {name}
      </li>
    );
  }
}

actions/actionTypes.js

export const CHANGE_LIST = "CHANGE_LIST";
export const TOGGLE_ITEM = "TOGGLE_ITEM";

actions/index.js

import * as TYPES from "./actionTypes";

// mock data
import _list from "./list.json";

// 获取列表数据
const receiveList = list => ({
  type: TYPES.CHANGE_LIST,
  list
});
export const changeList = () => dispatch => {
  setTimeout(() => {
    dispatch(receiveList(_list));
  }, 100);
};

//切换子项显示
export const toggleItem = id => ({
  type: TYPES.TOGGLE_ITEM,
  id
});

list.json

[
  {
    "id": 1,
    "name": "Apple",
    "removed": false
  },
  {
    "id": 2,
    "name": "Banana",
    "removed": false
  },
  {
    "id": 3,
    "name": "Orange",
    "removed": true
  }
]

reducers/index.js

import * as TYPES from "../actions/actionTypes";

const list = (state = [], action) => {
  switch (action.type) {
    case TYPES.CHANGE_LIST:
      return action.list;
    case TYPES.TOGGLE_ITEM:
    console.log("")
      return state.map(item => {
        return item.id === action.id ? { ...item, removed: !item.removed } : item;
      });
    default:
      return state;
  }
};

export default list;

6、业界其他数据管理方案,例如,mobx

demo使用库的版本如下:

 

 

总结

react通信方式有较多选择,需要根据具体的业务选择合适的数据传递方式,当交互较为复杂,共享数据多,引入redux是明智的决定

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值