成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

React 全局狀態管理的三種底層機制

開發 架構
現在前端頁面的開發方式是把頁面按照邏輯拆成一個個組件,分別開發每一個組件,然后層層組裝起來,傳入 ReactDOM.render 或者 Vue 的 $mount 來渲染。

[[423647]]

現代前端框架都是基于組件的方式來開發頁面。按照邏輯關系把頁面劃分為不同的組件,分別開發不同的組件,然后把它們一層層組裝起來,把根組件傳入 ReactDOM.render 或者 vue 的 $mount 方法中,就會遍歷整個組件樹渲染成對應的 dom。

組件都支持傳遞一些參數來定制,也可以在內部保存一些交互狀態,并且會在參數和狀態變化以后自動的重新渲染對應部分的 dom。

雖然從邏輯上劃分成了不同的組件,但它們都是同一個應用的不同部分,難免要彼此通信、配合。超過一層的組件之間如果通過參數通信,那么中間那層組件就要透傳這些參數。而參數本來是為了定制組件用的,不應該為了通信而添加一些沒意義的參數。

所以,對于組件的通信,一般不會通過組件參數的層層傳遞,而是通過放在全局的一個地方,雙方都從那里存取的方式。

具體的用于全局狀態管理的方案可能有很多,但是他們的底層無外乎三種機制:props、context、state。

下面,我們分別來探究一下這三種方式是如何做全局狀態的存儲和傳遞的。

props

我們可以通過一個全局對象來中轉,一個組件向其中存放數據,另一個組件取出來的方式來通信。

組件里面寫取 store 中數據的代碼比較侵入式,總不能每個用到 store 的組件都加一段這些代碼吧。我們可以把這些邏輯抽成高階組件,用它來連接(connect)組件和 store。通過參數的方式來把數據注入到組件中,這樣,對組件來說來源是透明的。

這就是 react-redux 做的事情:

  1. import { connect } from 'react-redux'
  2.  
  3. function mapStateToProps(state) { 
  4.     return { todos: state.todos } 
  5.    
  6. function mapDispatchToProps(dispatch) { 
  7.     return bindActionCreators({ addTodo }, dispatch) 
  8.    
  9. export default connect(mapStateToProps, mapDispatchToProps)(TodoApp) 

此外,redux 還提供了中間件機制,可以攔截組件發送給 store 的 action 來執行一系列異步邏輯。

 

比較流行的中間件有 redux-thunk、redux-saga、redux-obervable,分別支持不同的方式來寫組織異步流程,封裝和復用異步邏輯。

類似的其他全局狀態管理的庫,比如 mobox、reconcil 等,也是通過 props 的方式注入全局的狀態到組件中。

context

跨層組件通信一定要用第三方的方案么,不是的,react 本身也提供了 context 機制用于這種通信。

React.createContext 的 api 會返回 Provider 和 Consumer,分別用于提供 state 和取 state,而且也是通過 props 來透明的傳入目標組件的。(這里的 Consumer 也可以換成 useContext 的 api,作用一樣,class 組件用 Provider,function 組件用 useContext)

看起來和 redux 的方案基本沒啥區別,其實最主要的區別是 context 沒有執行異步邏輯的中間件。

所以 context 這種方案適合沒有異步邏輯的那種全局數據通信,而 redux 適合組織復雜的異步邏輯。

案例代碼如下:

  1. const themes = { 
  2.   light: { 
  3.     foreground: "#000000"
  4.     background: "#eeeeee" 
  5.   }, 
  6.   dark: { 
  7.     foreground: "#ffffff"
  8.     background: "#222222" 
  9.   } 
  10. }; 
  11.  
  12. const ThemeContext = React.createContext(themes.light); 
  13.  
  14. function App() { 
  15.   return ( 
  16.     <ThemeContext.Provider value={themes.dark}> 
  17.       <Toolbar /> 
  18.     </ThemeContext.Provider> 
  19.   ); 
  20.  
  21. function Toolbar(props) { 
  22.   return ( 
  23.     <div> 
  24.       <ThemedButton /> 
  25.     </div> 
  26.   ); 
  27.  
  28. function ThemedButton() { 
  29.   const theme = useContext(ThemeContext); 
  30.   return ( 
  31.     <button style={{ background: theme.background, color: theme.foreground }}> 
  32.       I am styled by theme context! 
  33.     </button> 
  34.   ); 

不知道大家有沒有想過,props、state 改變了,重新渲染組件很正常,context 改變了,又是怎么觸發渲染的呢?

其實 react 內部做了處理,如果改變了 context 的值,那么會遍歷所有的子組件,找到用到 context 值的組件,觸發它的更新。

所以,props、state、context 都能夠觸發重新渲染。

state

redux 和 context 的方案,一個是第三方的,一個是內置的,都是通過 props 來傳入值或者通過 hooks 來取值,但它們都是組件外部的,而 state 是組件內部的,怎么通過 state 來做全局狀態共享呢?

其實 class 組件的 state 做不到,但是 function 組件的 state 可以,因為它是通過 useState 的 hooks api 創建的,而 useState 可以抽離到自定義 hooks 里,然后不同的 function 組件里引入來用。

  1. import React, { useState } from 'react'
  2.  
  3. const useGlobalState = (initialValue) => { 
  4.     const [globalState, setGlobalState] = useState(initialValue); 
  5.     return [globalState, setGlobalState]; 
  6.  
  7. function ComponentA() { 
  8.     const [globalState, setGlobalState] = useGlobalState({name'aaa'}); 
  9.      
  10.     setGlobalState({name: bbb}); 
  11.     return <div>{globalState}</div> 
  12.  
  13. function ComponentA() { 
  14.     const [globalState, setGlobalState] = useGlobalState({name'aaa'}); 
  15.   
  16.     return <div>{globalState}</div> 

上面這段代碼可以共享全局狀態?

確實不可以,因為現在每個組件都是在自己的 fiber.memorizedState 中放了一個新的對象,修改也是修改各自的。

那把這兩個 useState 的初始值指向同一個對象不就行了?

這樣多個組件之間就可以操作同一份數據了。

上面的代碼要做下修改:

  1. let globalVal  = { 
  2.     name'' 
  3.  
  4. const useGlobalState = () => { 
  5.     const [globalState, setGlobalState] = useState(globalVal); 
  6.  
  7.     function updateGlobalState(val) { 
  8.         globalVal = val; 
  9.         setGlobalState(val); 
  10.     } 
  11.  
  12.     return [globalState, updateGlobalState]; 

這樣,每個組件創建的 state 都指向同一個對象,也能做到全局狀態的共享。

但這里有個前提,就是只能修改對象的屬性,而不能修改對象本身。

總結

現在前端頁面的開發方式是把頁面按照邏輯拆成一個個組件,分別開發每一個組件,然后層層組裝起來,傳入 ReactDOM.render 或者 Vue 的 $mount 來渲染。

組件可以通過 props 來定制,通過 state 來保存交互狀態,這些變了都會自動的重新渲染。除此之外,context 變了也會找到用到 contxt 數據的子組件來觸發重新渲染。

組件之間彼此配合,所以難免要通信,props 是用于定制組件的,不應該用來透傳沒意義的 props,所以要通過全局對象來中轉。

react 本身提供了 context 的方案,createContext 會返回 Provider 和 Consumer,分別用來存放和讀取數據。在 function 組件中,還可以用 useContext 來代替 Provider。

context 雖然可以共享全局狀態,但是卻沒有異步邏輯的執行機制,當有復雜的異步邏輯的時候,還是得用 redux 這種,它提供了中間件機制用于組織異步流程、封裝復用異步邏輯,比如 redux-saga 中可以把異步邏輯封裝成 saga 來復用。

context 和 redux 都支持通過 props 來注入數據到組件中,這樣對組件是透明的、無侵入的。

其實通過 useState 封裝的 自定義 hooks 也可以通過把初始值指向同一個對象的方式來達到全局數據共享的目的,但是是有限制的,只能修改對象的屬性,不能修改對象本身。其實用這種還不如用 context,只是提一下可以這樣做。

簡單總結一下就是:context 和 redux 都可以做全局狀態管理,一個是內置的,一個是第三方的,沒有異步邏輯用 context,有異步邏輯用 redux。

 

責任編輯:姜華 來源: 神光的編程秘籍
相關推薦

2022-03-29 20:10:27

React狀態管理

2009-09-25 15:58:04

Hibernate對象

2021-08-26 17:27:06

視圖VUE.JS網絡開發

2010-08-13 15:08:55

Flex數據訪問

2010-08-27 13:50:12

DB2安全機制

2010-04-16 15:12:12

ORACLE鎖機制

2010-08-09 15:09:27

Flex數據訪問

2010-09-30 11:20:35

DB2表靜默狀態

2020-10-15 06:28:08

React 5管理庫狀態

2010-04-27 12:42:45

LVS負載均衡

2011-01-18 15:35:59

jQueryJavaScriptweb

2023-03-06 08:40:43

RedisListJava

2025-01-10 08:15:22

C#異步底層

2010-09-24 19:18:22

SQL索引

2009-07-02 09:28:07

Hibernate三種

2019-02-27 07:45:25

物聯網健康管理IOT

2009-10-13 15:43:03

網絡拓撲管理

2023-02-24 16:45:02

2009-11-24 18:15:37

博科資訊管理軟件

2020-08-12 08:51:19

Go語言Concurrency后臺
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 中文字幕一区二区三区四区 | 中文字幕一二三 | 成人a视频片观看免费 | 一久久久 | 久久精品网 | 精品一二| 日韩欧美视频 | 午夜小电影 | 在线免费国产视频 | 一区二区三区国产 | 四虎成人精品永久免费av九九 | 国产片一区二区三区 | 成人伊人网 | 久久久久久久综合色一本 | 男女免费网站 | 国产一区二区三区 | 日韩精品一区二区三区中文在线 | 精品av| 色吊丝2 | 久久久亚洲综合 | 亚洲手机在线 | 精品国产99 | 国产精品日韩欧美一区二区 | 国产98色在线 | 日韩 | 一区二区三区在线观看视频 | 亚洲二区在线 | 狠狠ri | 国产精品久久一区二区三区 | 久久精品国产亚洲 | 亚洲国产免费 | 成人黄色av网址 | 日韩欧美专区 | www.亚洲精品| 亚洲精品乱码久久久久久按摩观 | 美女一区 | 日韩高清黄色 | 成人午夜精品一区二区三区 | 免费一区 | 日韩成人免费av | 国产精品美女 | 亚洲一区视频在线 |