React - 组件通信
1. 分类:
父子组件通信
子父组件通信
非父子组件通信
跨组件通信
多组件状态共享
2. 父组件与子组件通信
- 父组件将自己的状态传递给子组件,子组件当做属性来接收,当父组件更改自己状态的时候,子组件接收到的属性就会发生改变
- 父组件利用ref对子组件做标记,通过调用子组件的方法以更改子组件的状态,也可以调用子组件的方法..
/* Father.js如下 */
import React, { Component } from 'react'
import Son from './Son'
export default class Father extends Component {
constructor(props) {
super(props)
this.state = {
money: 2000
}
}
render() {
const { money } = this.state
return (
<div>
<Son money = { money } />
</div>
)
}
}
/* Son.js定义如下 */
import React, { Component } from 'react'
export default class Son extends Component {
render() {
const { money } = this.props
return (
<div>
<p> 老爸给了我: { money } </p>
</div>
)
}
}
3. 子组件与父组件通信
- 父组件将自己的某个方法传递给子组件,在方法里可以做任意操作,比如可以更改状态,子组件通过this.props接收到父组件的方法后调用。
/* Father组件定义如下 */
import React, { Component } from 'react'
import OneOne from './OneOne'
export default class One extends Component {
constructor(props) {
super(props)
this.state = {
jk: 0
}
}
changeJk = val => {
this.setState({
jk: val
})
}
render() {
const { jk } = this.state
return (
<div>
<OneOne changeJk = { this.changeJk }/>
<p> 儿子给了我 { jk } 红包 </p>
</div>
)
}
}
/* Son组件定义如下 */
import React, { Component } from 'react'
export default class OneOne extends Component {
constructor(props) {
super(props)
this.state = {
hongbao: 80000
}
}
render() {
const { changeJk } = this.props
const { hongbao } = this.state
return (
<div>
<button onClick = {() => { changeJk( hongbao ) }}> 给红包 </button>
</div>
)
}
}
4. 跨组件通信
在react没有类似vue中的事件总线来解决这个问题,我们只能借助它们共同的父级组件来实现,将非父子关系装换成多维度的父子关系。react提供了context api来实现跨组件通信, React 16.3之后的contextapi较之前的好用。
实例,使用context 实现购物车中的加减功能
class App extends React.Component {
render() {
return <Toolbar theme="dark" />;
}
}
function Toolbar(props) {
// Toolbar 组件接受一个额外的“theme”属性,然后传递给 ThemedButton 组件。
// 如果应用中每一个单独的按钮都需要知道 theme 的值,这会是件很麻烦的事,
// 因为必须将这个值层层传递所有组件。
return (
<div>
<ThemedButton theme={props.theme} />
</div>
);
}
class ThemedButton extends React.Component {
render() {
return <Button theme={this.props.theme} />;
}
}
// Context 可以让我们无须明确地传遍每一个组件,就能将值深入传递进组件树。
// 为当前的 theme 创建一个 context(“light”为默认值)。
const ThemeContext = React.createContext('light');
class App extends React.Component {
render() {
// 使用一个 Provider 来将当前的 theme 传递给以下的组件树。
// 无论多深,任何组件都能读取这个值。
// 在这个例子中,我们将 “dark” 作为当前的值传递下去。
return (
<ThemeContext.Provider value="dark">
<Toolbar />
</ThemeContext.Provider>
);
}
}
// 中间的组件再也不必指明往下传递 theme 了。
function Toolbar(props) {
return (
<div>
<ThemedButton />
</div>
);
}
class ThemedButton extends React.Component {
// 指定 contextType 读取当前的 theme context。
// React 会往上找到最近的 theme Provider,然后使用它的值。
// 在这个例子中,当前的 theme 值为 “dark”。
static contextType = ThemeContext;
render() {
return <Button theme={this.context} />;
}
}
5. 非父子组件通信
/* Father.js定义如下 */
import React, { Component } from 'react'
import Brother from './Brother'
import Sister from './Sister'
export default class Father extends Component {
/* 父组件 */
cry = () => {
// this.refs.brother.cry()
this.brother.cry()
}
render() {
return (
<div>
<Sister cry = { this.cry }/>
{/* <Brother ref = "brother"/> */}
<Brother ref = { el => this.brother = el }/>
</div>
)
}
}
/* Brother.js定义如下 */
import React, { Component } from 'react'
export default class Brother extends Component {
constructor(props) {
super(props)
this.state = {
f: false
}
}
cry = () => {
this.setState({
f: true
})
}
render() {
const { f } = this.state
return (
<div>
{ f && <img src = "http://5b0988e595225.cdn.sohucs.com/q_70,c_zoom,w_640/images/20180113/db7a23a0460c4ffe80533a64c47c94ee.gif" />}
</div>
)
}
}
/* Sister组件定义如下 */
import React, { Component } from 'react'
export default class Sister extends Component {
hick = () => {
//执行揍弟弟
}
render() {
const { cry } = this.props
return (
<div>
<button onClick = { cry }> 揍弟弟 </button>
</div>
)
}
}
5. 状态管理
说明: 状态管理我们将在后面讲解
复杂的非父子组件通信在react中很难处理,多组件间的数据共享也不好处理,在实际的工作中我们会使用flux、redux、mobx来实现