React 中元件之間的通訊方式
阿新 • • 發佈:2022-03-25
元件間通訊方式
在使用 React 的過程中,經常需要元件之間相互傳遞資訊,故記錄一下元件間的常用通訊方式:
-
父元件向子元件通訊
父元件向子元件傳遞 props, 子元件通過獲取 props 中的內容得到父元件傳遞的資訊;
示例:父元件(App)向子元件(Root)通訊import Root from "./components/Root"; const App = (props) => { return ( <div className="app"> {/* 向自定義元件(Root)設定(msg)屬性; 自定義元件(Root)會將所接收到的屬性(attributes)和子元件(children) 轉換為單個物件(props)傳遞給元件; */} <Root msg="this is a test message" /> </div> ); } // 父元件 App export default App;
const Root = (props) => { // 獲取父元件傳遞的msg屬性值 const msg = props.msg; return ( <div className="root"> {msg} {/* this is a test message */} </div> ); } // 子元件 Root export default Root;
-
子元件向父元件通訊
父元件向子元件傳遞一個回撥函式屬性, 子元件通過呼叫父元件傳遞的回撥函式實現子元件向父元件通訊;
示例:子元件(Root)向父元件(App)通訊import Root from "./components/Root"; const App = (props) => { const getName = (name) => { // my name is root console.log(name); } return ( <div className="app"> {/*向子元件傳遞callback屬性,屬性值為一個回撥函式 */} <Root callback={getName} /> </div> ); } // 父元件 App export default App;
const Root = (props) => { // 獲取父元件傳遞的callback屬性值(getName函式) const getName = props.callback; const name = "my name is Root"; // 呼叫getName函式 getName && getName(name); return null; } // 子元件 Root export default Root;
-
跨級元件間通訊
跨級元件是指父元件的子元件的子元件,或者更深層的巢狀關係,跨級元件之間想要通訊,有兩種常見方式:- 中間元件層層傳遞
- 使用 Context
示例:頂層元件 App 向"孫子"級元件 Content 通訊
import React from "react"; import Root from "./components/Root"; const App = (props) => { const context = { name: "趙雲" } return ( // Provider(生產者)共享容器,在頂層傳入value <App.Context.Provider value={context}> <div className="app"> <Root /> </div> </App.Context.Provider> ); } // 建立一個Context App.Context = React.createContext(); // 頂層元件 App export default App;
import Content from "./Content"; const Root = (props) => { return ( // 中間元件 <Content /> ); } // 中間元件 Root export default Root;
import App from '../App'; const Content = (props) => { return ( // Consumer(消費者)容器,可以獲取從頂層傳遞的context <App.Context.Consumer> {/* 以函式的方式使用context */} {context => ( <div className='content'> {context.name} {/* 趙雲 */} </div> )} </App.Context.Consumer> ); } // 目標通訊元件 Content export default Content;
-
非巢狀元件間通訊
非巢狀元件,就是通訊元件間沒有任何包含關係,包括兄弟元件以及不在同一個父級中的非兄弟元件;對於非巢狀元件,可以利用這兩種方式通訊:- 利用二者共同父元件的 context 物件進行通訊
- 使用自定義事件的方式
如果採用元件間共同的父級來進行中轉,會增加子元件和父元件之間的耦合度,如果元件層次較深的話,找到二者公共的父元件不是一件容易的事;
使用自定義事件的方式來實現非巢狀元件間的通訊。
示例:Root 元件向 Content 元件通訊
# 這裡需要一個 events 依賴來做釋出訂閱動作 npm install events --save
import React from "react"; import Root from "./components/Root"; import Content from "./components/Content"; const App = (props) => { return ( <div className="app"> <Root /> <Content /> </div> ); } // 頂層元件 App export default App;
import React from 'react'; import emitter from "./event"; const Root = (props) => { // 初始化 state, 相當於 class 元件中的 this.state = {rootName: ""} const [rootName, setRootName] = React.useState(""); // 監聽 setRootName 事件的回撥函式 const setRootNameCallback = (name) => { setRootName(name); } // 類似於類元件中的 componentDidMount React.useEffect(() => { emitter.addListener("setRootName", setRootNameCallback); }, []); // 類似於類組價中 componentWillUnmout React.useEffect(() => { // 元件解除安裝移除監聽 return () => { emitter.removeListener("setRootName", setRootNameCallback); } }); return ( // 兄弟元件 <div className="root"> {rootName} {/* 趙雲 */} </div> ); } // 兄弟元件 Root export default Root;
import React from "react"; import emitter from "./event"; const Content = (props) => { // 類似於類元件中的 componentDidMount React.useEffect(() => { // 觸發 setRootName 事件,向訂閱者傳值; emitter.emit("setRootName", "趙雲"); }, []); return ( // 兄弟元件 <div className="content"> </div> ); } // 兄弟元件 Content export default Content;
總結
本文記錄了不同巢狀關係的元件間常用的幾種通訊方式:
- 父子巢狀關係:利用 props 物件實現父元件向子元件通訊;
- 父子巢狀關係:利用 callback(回撥函式) 實現子元件向父元件通訊;
- 多層(父子)巢狀關係(跨級通訊):利用 Context 物件, 以生產者和消費者的方式實現通訊;
- 非巢狀關係:利用 events (釋出訂閱) 的方式實現通訊;
如果專案比較大,巢狀關係比較複雜,state 就會變得難以管理,就需要考慮使用 Redux 庫管理狀態;