亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

詳解React中的組件通信問題

 更新時間:2017年07月31日 10:12:59   投稿:zx  
本篇文章中主要介紹了詳解React中的組件通信問題,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧

引入

本來我是沒想過總結(jié)這些東西的,會感覺比較入門。但是之前同學去騰訊面試問到了這個問題(react或vue的組件通信),我?guī)退恚槺銓慸emo的過程中,會有一些新的體會,多總結(jié)還是有利于進步的呀。

父子組件

父 → 子

parent組件傳給child組件,符合react的單向數(shù)據(jù)流理念,自上到下傳遞props。

// 父組件
class Parent extends Component {
 constructor() {
  super();
  this.state = {
   value: '',
  }
 }

 handleChange = e => {
  this.value = e.target.value;
 }

 handleClick = () => {
  this.setState({
   value: this.value,
  })
 }

 render() {
  return (
   <div>
    我是parent
    <input onChange={this.handleChange} />
    <div className="button" onClick={this.handleClick}>通知</div>
    <div>
     <Child value={this.state.value} />
    </div> 
   </div>
  );
 }
}
// 子組件
class Child extends Component {
 render() {
  const { value } = this.props;
  return (
   <div>
    我是Child,得到傳下來的值:{value}
   </div>
  );
 }
}

父組件做的就是定義好 state ,定義好事件函數(shù),input onChange 的時候,去緩存 value 值,然后點擊 button 的時候,改變 state , 子組件只負責展示 value 。

子 → 父

child 組件通知 parent 組件, 主要是依靠 parent 傳下來的 callback 函數(shù)執(zhí)行,改變 parent 組件的狀態(tài),或者把 child 自己的 state 通知 parent 。分兩種情況:

state 定義在 parent 組件

// parent

class Parent extends Component {
 constructor() {
  super();
  this.state = {
   value: '',
  }
 }

 setValue = value => {
  this.setState({
   value,
  })
 }

 render() {
  return (
   <div>
    <div>我是parent, Value是:{this.state.value}</div> 
    <Child setValue={this.setValue} />
   </div>
  );
 }
}
class Child extends Component {

 handleChange = e => {
  this.value = e.target.value;
 }

 handleClick = () => {
  const { setValue } = this.props;
  setValue(this.value);
 }

 render() {
  return (
   <div>
    我是Child
    <div className="card">
     state 定義在 parent
     <input onChange={this.handleChange} />
     <div className="button" onClick={this.handleClick}>通知</div>
    </div>
   </div>
  );
 }
}

parent 組件把改變 state 的 setValue 函數(shù)傳給 child ,child 組件自己處理內(nèi)部的狀態(tài)(這里是表單的value值),當 child 組件分發(fā)消息的時候, 執(zhí)行 parent 的 setValue 函數(shù),從而改變了 parent 的 state,state發(fā)生變化, parent 組件執(zhí)行 re-render 。

state 定義在 child 組件

// parent

class Parent extends Component {

 onChange = value => {
  console.log(value, '來自 child 的 value 變化');
 }

 render() {
  return (
   <div>
    <div>我是parent
    <Child onChange={this.onChange} />
   </div>
  );
 }
}

class Child extends Component {

 constructor() {
  super();
  this.state = {
   childValue: ''
  }
 }

 childValChange = e => {
  this.childVal = e.target.value;
 }

 childValDispatch = () => {
  const { onChange } = this.props;
  this.setState({
   childValue: this.childVal,
  }, () => { onChange(this.state.childValue) })
 }

 render() {
  return (
   <div>
    我是Child
    <div className="card">
     state 定義在 child
     <input onChange={this.childValChange} />
     <div className="button" onClick={this.childValDispatch}>通知</div>
    </div>
   </div>
  );
 }
}

有時候 state 是需要定義在 child 組件的,比如彈窗, CheckBox 這種開關(guān)性質(zhì)的,邏輯是重復的,state 定義在組件內(nèi)部更好維護, 復用性更好。但是 child 的 state 是需要告知我的 parent 組件的, 同樣還是執(zhí)行 parent 傳下來的 change 函數(shù)。

兄弟組件

有時候可能出現(xiàn)頁面中的某兩部分通信,比如省市的級聯(lián)選擇,點擊 button 改變顏色等等,組件并不是父子級,沒有嵌套關(guān)系的時候。這種時候通常是依賴共有的頂級 Container 處理或者第三方的狀態(tài)管理器。其實原理都是相通的,兄弟 A 的 value 發(fā)生變化,分發(fā)的時候把 value 值告訴一個中間者 C ,C 會自動告知 B,實現(xiàn) B 的自動render 。

利用共有的Container

// container
class Container extends Component {
 constructor() {
  super();
  this.state = {
   value: '',
  }
 }

 setValue = value => {
  this.setState({
   value,
  })
 }

 render() {
  return (
   <div>
    <A setValue={this.setValue}/>
    <B value={this.state.value} />
   </div>
  );
 }
}

// 兄弟A
class A extends Component {

 handleChange = (e) => {
  this.value = e.target.value;
 }

 handleClick = () => {
  const { setValue } = this.props;
  setValue(this.value);
 }

 render() {
  return (
   <div className="card">
    我是Brother A, <input onChange={this.handleChange} />
    <div className="button" onClick={this.handleClick}>通知</div>
   </div>
  )
 }
}

// 兄弟B
const B = props => (
 <div className="card">
  我是Brother B, value是:
  {props.value}
 </div>
);
export default B;

組件 A 中的表單 value 值,告知了父級 Container 組件(通過 setValue 函數(shù)改變 state),組件 B 依賴于 Container 傳下來的 state,會做出同步更新。這里的中間者是 Container。

利用Context

上面的方式,如果嵌套少還可以,如果嵌套特別多,比如一級導航欄下的二級導航欄下的某個按鈕,要改變頁面中 content 區(qū)域的 table 里的某個列的值...他們同屬于一個 page 。這樣傳遞 props 就會很痛苦,每一層組件都要傳遞一次。

// 頂級公共組件
class Context extends Component {

 

 constructor() {
  super();
  this.state = {
   value: '',
  };
 }

 setValue = value => {
  this.setState({
   value,
  })
 }

 getChildContext() { // 必需
  return { 
   value: this.state.value,
   setValue: this.setValue,
  };
 }
 render() {
  return (
   <div>
    <AParent />
    <BParent />
   </div>
  );
 }
}
// 必需
Context.childContextTypes = {
 value: PropTypes.string,
 setValue: PropTypes.func,
};

// A 的 parent
class AParent extends Component {
 render() {
  return (
   <div className="card">
    <A />
   </div>
  );
 }
}
// A
class A extends Component {

 handleChange = (e) => {
  this.value = e.target.value;
 }

 handleClick = () => {
  const { setValue } = this.context;
  setValue(this.value);
 }

 render() {
  return (
   <div>
    我是parentA 下的 A, <input onChange={this.handleChange} />
    <div className="button" onClick={this.handleClick}>通知</div>
   </div>
  );
 }
}
// 必需
A.contextTypes = {
 setValue: PropTypes.func,
};

// B 的 parent
class BParent extends Component {
 render() {
  return (
   <div className="card">
    <B />
   </div>
  );
 }
}

// B
class B extends Component {

 render() {
  return (
   <div>
    我是parentB 下的 B, value是:
    {this.context.value}
   </div>
  );
 }
}

B.contextTypes = {
 value: PropTypes.string,
};

組件 A 仍是 消息的發(fā)送者,組件 B 是接收者, 中間者是 Context 公有 Container 組件。context是官方文檔的一個 API ,通過 getChildContext 函數(shù)定義 context 中的值,并且還要求 childContextTypes 是必需的。這樣屬于這個 Container 組件的子組件,通過 this.context 就可以取到定義的值,并且起到跟 state 同樣的效果。中間者其實還是 Container,只不過利用了上下文這樣的 API ,省去了 props 的傳遞。另外:這個功能是實驗性的,未來可能會有所改動。

發(fā)布訂閱

這種一個地方發(fā)送消息,另一個地方接收做出變化的需求,很容易想到的就是觀察者模式了。具體的實現(xiàn)會有很多種,這里我們自己寫了一個 EventEmitter 的類(其實就是仿照 node 中的 EventEmitter 類),如果不了解觀察者,可以看我的另一篇文章 觀察者模式 。

// 發(fā)布訂閱類
class EventEmitter {
 _event = {}

 // on 函數(shù)用于綁定
 on(eventName, handle) {
  let listeners = this._event[eventName];
  if(!listeners || !listeners.length) {
   this._event[eventName] = [handle];
   return;
  }
  listeners.push(handle);
 }
 // off 用于移除
 off(eventName, handle) {
  let listeners = this._event[eventName];
  this._event[eventName] = listeners.filter(l => l !== handle);
 }
 // emit 用于分發(fā)消息
 emit(eventName, ...args) {
  const listeners = this._event[eventName];
  if(listeners && listeners.length) {
   for(const l of listeners) {
    l(...args);
   }
  }
 }
}
const event = new EventEmitter;
export { event };

// Container
import A from './a';
import B from './b';

const Listener = () => {
 return (
  <div>
   <A />
   <B />
  </div>
 );
};
export default Listener;

// 兄弟組件 A
import { event } from './eventEmitter';

class A extends Component {

 handleChange = e => {
  this.value = e.target.value;
 }

 handleClick = () => {
  event.emit('dispatch', this.value);
 }

 render() {
  return (
   <div className="card">
    我是Brother A, <input onChange={this.handleChange} />
    <div className="button" onClick={this.handleClick}>通知</div>
   </div>
  )
 }
}

// 兄弟組件 B
import { event } from './eventEmitter';

class B extends Component {
 state = {
  value: ''
 }

 componentDidMount() {
  event.on('dispatch', this.valueChange);
 }

 componentWillUnmount() {
  event.off('dispatch', this.valueChange);
 }

 valueChange = value => {
  this.setState({
   value,
  })
 }

 render() {
  return (
   <div className="card">
    我是Brother B, value是:
    {this.state.value}
   </div>
  );
 }
}

仍然是組件 A 用于分發(fā)消息,組件 B 去接收消息。這里的中間者其實就是 event 對象。需要接收消息的 B 去訂閱 dispatch 事件,并把回調(diào)函數(shù) valueChange 傳入,另外 B 定義了自己的 state,方便得到 value 值的時候自動渲染。組件 A 其實就是把內(nèi)部的表單 value 在點擊的時候分發(fā),發(fā)布事件,從而 B 中的 valueChange 執(zhí)行,改變 state。這種方式比較方便,也更直觀,不需要借助 Container 組件去實現(xiàn),省去了很多邏輯。

Redux || Mobx

Redux 或者 Mobx 是第三方的狀態(tài)管理器,是這里我們通信的中間者。大型項目最直接的就是上庫... 更方便,更不容易出錯。 但其實小項目就沒什么必要了。東西比較多,這里不再闡述它們的實現(xiàn)和做了什么。

總結(jié)

react 特殊的自上而下的單向數(shù)據(jù)流,和 state 的特性,造就以這樣的思想實現(xiàn)組件通信。除去發(fā)布訂閱和 Redux 等,其他的都是 props 自上而下傳遞的理念,子組件需要的總是通過父組件傳遞下來的,關(guān)于 state 的定義,還是看具體的應用場景了。

另外本次的代碼都放在https://github.com/sunyongjian/rc-communication-demo, 可以 done 下來加深理解。

以上就是本文的全部內(nèi)容,希望對大家的學習有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • React useReducer終極使用教程

    React useReducer終極使用教程

    useReducer是在react V16.8推出的鉤子函數(shù),從用法層面來說是可以代替useState。相信前期使用過 React 的前端同學,大都會經(jīng)歷從class語法向hooks用法的轉(zhuǎn)變,react的hooks編程給我們帶來了絲滑的函數(shù)式編程體驗
    2022-10-10
  • react中實現(xiàn)修改input的defaultValue

    react中實現(xiàn)修改input的defaultValue

    這篇文章主要介紹了react中實現(xiàn)修改input的defaultValue方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-05-05
  • 淺談react-native熱更新react-native-pushy集成遇到的問題

    淺談react-native熱更新react-native-pushy集成遇到的問題

    下面小編就為大家?guī)硪黄獪\談react-native熱更新react-native-pushy集成遇到的問題。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-09-09
  • react高階組件添加和刪除props

    react高階組件添加和刪除props

    這篇文章主要介紹了react高階組件添加和刪除props,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2019-04-04
  • 解決配置setupProxy.js代理,頁面報錯404問題

    解決配置setupProxy.js代理,頁面報錯404問題

    這篇文章主要介紹了解決配置setupProxy.js代理,頁面報錯404問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-07-07
  • 淺談webpack+react多頁面開發(fā)終極架構(gòu)

    淺談webpack+react多頁面開發(fā)終極架構(gòu)

    這篇文章主要介紹了淺談webpack+react多頁面開發(fā)終極架構(gòu),小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-11-11
  • React+EggJs實現(xiàn)斷點續(xù)傳的示例代碼

    React+EggJs實現(xiàn)斷點續(xù)傳的示例代碼

    這篇文章主要介紹了React+EggJs實現(xiàn)斷點續(xù)傳的示例代碼,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2020-07-07
  • 一文詳解如何使用React監(jiān)聽網(wǎng)絡狀態(tài)

    一文詳解如何使用React監(jiān)聽網(wǎng)絡狀態(tài)

    在現(xiàn)代Web應用程序中,網(wǎng)絡連接是至關(guān)重要的,通過監(jiān)聽網(wǎng)絡狀態(tài),我們可以為用戶提供更好的體驗,例如在斷網(wǎng)時顯示有關(guān)網(wǎng)絡狀態(tài)的信息,本文將介紹如何使用React監(jiān)聽網(wǎng)絡狀態(tài)的變化,并提供相應的代碼示例
    2023-06-06
  • React組件對子組件children進行加強的方法

    React組件對子組件children進行加強的方法

    這篇文章主要給大家介紹了關(guān)于React組件中對子組件children進行加強的相關(guān)資料,文中通過示例代碼介紹的非常詳細,對大家學習或者使用React具有一定的參考學習價值,需要的朋友們下面來一起學習學習吧
    2019-06-06
  • React中映射一個嵌套數(shù)組實現(xiàn)demo

    React中映射一個嵌套數(shù)組實現(xiàn)demo

    這篇文章主要為大家介紹了React中映射一個嵌套數(shù)組實現(xiàn)demo,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-12-12

最新評論