51工具盒子

依楼听风雨
笑看云卷云舒,淡观潮起潮落

React组件之间的通信

React 的组件相对于 Vue 更加的灵活和多样,按照不同的方式可以分成很多类组件:

  • 根据组件的定义方式,可以分为:函数组件(Functional Component )类组件(Class Component)
  • 根据组件内部是否有状态需要维护,可以分成:无状态组件(Stateless Component )有状态组件(Stateful Component)
  • 根据组件的不同职责,可以分成:展示型组件(Presentational Component)容器型组件(Container Component)

React 中的组件之间的通信方法。

父子组件通信 {#父子组件通信}

下面这个案例演示了子传父父传子通过 props 传递。

父组件

|---------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | import React, { Component } from "react"; import Header from "./Header"; import Footer from "./Footer"; import Main from "./Main"; class App extends Component { constructor() { super(); this.state = { title: "Header的标题", }; } headerClick() { console.log("----"); } render() { const { title } = this.state; return ( <div> <Header title={title} headerClick={() => this.headerClick()} /> <Main /> <Footer /> </div> ); } } export default App; |

子组件

|------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | import React, { Component } from "react"; export class Header extends Component { // constructor(props) { // super(props) // this.state = {} // } render() { const { title, headerClick } = this.props; return <div onClick={headerClick}>Header: {title}</div>; } } export default Header; |

非父子组件通信 {#非父子组件通信}

非父子组件数据的共享
在开发中,比较常见的数据传递方式是通过 props 属性自上而下(由父到子)进行传递。
但是对于有一些场景:比如一些数据需要在多个组件中进行共享(地区偏好、UI 主题、用户登录状态、用户信息等)。
如果我们在顶层的 App 中定义这些信息,之后一层层传递下去,那么对于一些中间层不需要数据的组件来说,是一种冗余的操作。

React 提供了一个 API:Context
Context 提供了一种在组件之间共享此类值的方式,而不必显式地通过组件树的逐层传递 props
Context 设计目的是为了共享那些对于一个组件树而言是"全局"的数据,例如当前认证的用户、主题或首选语言;

可以使用Context或者eventBus

React.createContext {#React-createContext}

创建一个需要共享的 Context 对象:

如果一个组件订阅了 Context,那么这个组件会从离自身最近的那个匹配的 Provider 中读取到当前的 context 值;
defaultValue 是组件在顶层查找过程中没有找到对应的 Provider,那么就使用默认值

|-----------|--------------------------------------------------------------| | 1 | const MyContext = React.createContext(defaultValue); |

Context.Provider {#Context-Provider}

每个 Context 对象都会返回一个 Provider React 组件,它允许消费组件订阅 context 的变化:

Provider 接收一个 value 属性,传递给消费组件;
一个 Provider 可以和多个消费组件有对应关系;
多个 Provider 也可以嵌套使用,里层的会覆盖外层的数据;
当 Provider 的 value 值发生变化时,它内部的所有消费组件都会重新渲染;

|-----------|--------------------------------------------------| | 1 | <MyContext.Provider value={/* 某个值 */} /> |

案例 {#案例}

以下案例同时演示ContexteventBus

context.jsx

|---------------|---------------------------------------------------------------------------------------------------------------| | 1 2 3 | import React from "react"; export const UserContext = React.createContext({ name: "kobe", age: 30 }); |

app.jsx

|------------------------------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | import React, { Component } from "react"; import Home from "./Home"; import Recommend from "./Recommend"; import { UserContext } from "./context"; import eventBus from "./event/event_bus"; class App extends Component { constructor() { super(); this.state = { name: "anzhiyu", }; } componentDidMount() { eventBus.on("changeName", this.productClick, this); } componentWillUnmount() { eventBus.off("changeName", this.productClick); } productClick(name, age) { console.log("productClick", name, age, this); this.setState({ name: name }); } render() { return ( <div className="app"> <UserContext.Provider value={{ name: "安知鱼", level: 100 }}> <Home /> <Recommend /> </UserContext.Provider> <h2>{this.state.name}</h2> </div> ); } } export default App; |

Home.jsx

|------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 | import React, { Component } from "react"; import HomeProduct from "./HomeProduct"; class Home extends Component { render() { return ( <div> <HomeProduct /> </div> ); } } export default Home; |

HomeProduct.jsx

|------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | import React, { Component } from "react"; import { UserContext } from "./context"; import eventBus from "./event/event_bus"; class HomeProduct extends Component { productClick() { eventBus.emit("changeName", "安知鱼变帅", 18); } render() { console.log(this.context); return ( <div> <div>HomeProduct</div> <button onClick={e => this.productClick()}>product</button> </div> ); } } HomeProduct.contextType = UserContext; export default HomeProduct; |

Recommend.jsx 演示 函数式组件 Consumer

|---------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | import { UserContext } from "./context"; function Recommend(props) { return ( <div> <span>Recommend</span> {/* 函数式组件中使用Context共享的数据 */} <UserContext.Consumer> {value => { return <span>{value.name}</span>; }} </UserContext.Consumer> </div> ); } export default Recommend; |

如果需要使用多个 context 可以使用Consumer共享

theme-context.js

|---------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------| | 1 2 3 4 5 6 | import React from "react"; // 1.创建一个Context const ThemeContext = React.createContext({ color: "blue", size: 10 }); export default ThemeContext; |

user-context.js

|---------------------|----------------------------------------------------------------------------------------------------------------------------| | 1 2 3 4 5 6 | import React from "react"; // 1.创建一个Context const UserContext = React.createContext(); export default UserContext; |

HomeInfo.jsx

|------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | import React, { Component } from "react"; import ThemeContext from "./context/theme-context"; import UserContext from "./context/user-context"; export class HomeInfo extends Component { render() { // 4.第四步操作: 获取数据, 并且使用数据 console.log(this.context); return ( <div> <h2>HomeInfo: {this.context.color}</h2> <UserContext.Consumer> {value => { return <h2>Info User: {value.nickname}</h2>; }} </UserContext.Consumer> </div> ); } } // 3.第三步操作: 设置组件的contextType为某一个Context HomeInfo.contextType = ThemeContext; export default HomeInfo; |

context 默认数据 {#context-默认数据}

当没有被 context 组件包裹时就会使用到默认数据

theme-context.js

|---------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------| | 1 2 3 4 5 6 | import React from "react"; // 1.创建一个Context const ThemeContext = React.createContext({ color: "blue", size: 10 }); export default ThemeContext; |

App.jsx

|------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | import React, { Component } from "react"; import Home from "./Home"; import ThemeContext from "./context/theme-context"; import UserContext from "./context/user-context"; import Profile from "./Profile"; export class App extends Component { constructor() { super(); this.state = { info: { name: "kobe", age: 30 }, }; } render() { const { info } = this.state; return ( <div> <h2>App</h2> <UserContext.Provider value={{ nickname: "kobe", age: 30 }}> <ThemeContext.Provider value={{ color: "red", size: "30" }}> <Home {...info} /> </ThemeContext.Provider> </UserContext.Provider> <Profile /> </div> ); } } export default App; |

Profile.jsx

|------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 | import React, { Component } from "react"; import ThemeContext from "./context/theme-context"; export class Profile extends Component { render() { console.log(this.context); return <div>Profile</div>; } } Profile.contextType = ThemeContext; export default Profile; |

赞(1)
未经允许不得转载:工具盒子 » React组件之间的通信