開源不易,感謝你的支持,❤ star concent^_^vue
[Concent速成]是一個幫助新手極速入門concent
的系列文章,0障礙地學習和理解concent狀態管理思路。react
雖然學習和使用過redux
和mbox
之類的狀態管理庫,閱讀此篇文章會更容易理解,可是沒有使用過任何狀態管理庫的用戶也能極速入門concent
,真正的0障礙學會使用它並接入到你的react應用裏。git
注意上面強調了0障礙,包括了學會使用和接入應用兩個方面,爲了達到此目的,api要足夠簡單,簡單到什麼程度呢?簡單到無以復加,簡單到和react
保持100%一致,讓新手無需理解額外的概覽,以react組件的編寫方式就能接入狀態管理,可是呢也保留了更高級的抽象接口,讓老手能夠按照redux
的模式去組織代碼。github
來吧,展現!本期講解的關鍵api,包括一個3個頂層apirun
、useConcent
、register
,一個實例上下文apisetState
,學會使用這4個api,你就已經會使用concent作爲你的狀態管理方案了。json
全部的框架都會以Hello world
做爲引導,咱們此處也不例外,看看concent
版本的Hello world
是多麼的簡單。redux
concent和redux同樣,有一個全局單一的狀態樹,是一個普通的json對象,不過第一層key規劃爲模塊名,來幫助用戶按照業務場景將狀態切分爲多個模塊,便於分開管理。api
此處咱們須要用到run
接口啓動concent並載入模塊配置,配置一個名爲hello
的模塊,併爲其定義狀態數組
import { run } from 'concent'; run({ hello: { state: { greeting: 'Hello world' }, }, });
定義好了模塊,咱們的組件須要消費模塊的狀態,對於類組件,使用register
便可架構
import { register } from 'concent'; @register('hello') class HelloCls extends React.Component{ state = { greeting: '' }; changeGreeting = (e)=> this.setState({greeting: e.target.value}) render(){ return <input value={this.state.greeting} onChange={this.changeGreeting} /> } }
上訴代碼用register
接口將HelloCls
組件註冊屬於hello
模塊,concent將向當前組件this
上注入一個實例上下文ctx
,用於讀取數據和調用修改方法,同時也默默替換了this上的state
和setState
,方便用戶能夠0改動原組件的代碼,僅使用register
裝飾一下類組件便可接入狀態管理,這就是0障礙學會使用並接入到react應用的基礎,對於初學者來講,你會寫react組件,就已經會使用了concent,沒有任何額外的學習成本。框架
this.state === this.ctx.state; // true this.setState === this.ctx.setState; // true
上述代碼裏,還聲明瞭一個類成員變量state
等於 { greeting: '' }
,由於greeting
和模塊狀態裏的重名了,因此首次渲染以前它的值將被替換爲模塊裏的Hello world
,實際上這裏能夠不聲明這個類成員變量state
,寫上它只是爲了保證刪除register
裝飾器這個組件也能正常工做,而不會獲得一個undefined
的greeting
初始值。
使用useConcent
接口註冊當前組件所屬模塊,useConcent
會返回當前組件的實例上下文對象ctx
,等同於上面類組件的this.ctx
,咱們只須要解構它取出state
和setState
便可。
import { useConcent } from 'concent'; function HelloFn(){ const { state, setState } = useConcent('hello'); const changeGreeting = (e)=> setState({greeting: e.target.value}) return <input value={state.greeting} onChange={changeGreeting} /> }
最後咱們看下完整的代碼吧,咱們發現頂層無Provider
之類的組件包裹根組件,由於concent沒有依賴React Context api
實現狀態管理,而是本身獨立維護了一個獨立的全局上下文,因此你在已有的項目裏接入concent是很是容易的,即插即用,無需任何額外的改造。
因爲HelloCls
和HelloFn
組件都屬於hello
模塊,它們中的任意一個實例修改模塊狀態,concent會將其存儲到store,並同步到其它同屬於hello
模塊的實例上,狀態共享就是這麼簡單。
import ReactDOM from 'react-dom'; import { run } from 'concent'; import { register, useConcent } from 'concent'; run({/** 略 */}); @register('hello') class HelloCls extends React.Component{/** 略 */} function HelloFn(){/** 略 */} const App = ()=>( <div> <HelloCls /> <HelloFn /> </div> ); ReactDOM.render(App, document.getElementById('root'));
不管是類組件仍是函數組件,拿到state
對象已被轉換爲一個Proxy
代理對象,負責收集當前渲染的數據依賴,因此若是是有條件判斷的讀取狀態,推薦採用延遲解構的寫法,讓每一次渲染都鎖定最小的依賴列表,減小冗餘渲染,得到更好的性能。
function HelloFn(){ const { state, setState, syncBool } = useConcent({module:'hello', state:{show:true}}); const changeGreeting = (e)=> setState({greeting: e.target.value}); // 當show爲true時,當前實例的依賴是['greeting'],其餘任意地方修改了greeting值都會觸發當前實例重渲染 // 當show爲false時,當前實例無依賴,其餘任意地方修改了greeting值不會影響當前實例重渲染 return ( <> {state.show?<input value={state.greeting} onChange={changeGreeting} />:'no input'} <button onClick={syncBool('show')}>toggle show</button> </> ); }
當組件須要消費多個模塊的數據時,可以使用connect
參數來聲明要鏈接的多個模塊。
以下面示例,鏈接bar和baz兩個模塊,經過ctx.connectedState
獲取目標模塊狀態:
@register({connect:['bar', 'baz']}) class extends React.Component{ render(){ const { bar, baz } = this.ctx.connectedState; } }
從
connectedState
拿到的模塊狀態依然存在着依賴收集行爲,因此若是存在條件渲染語句,推薦延遲解構寫法
經過調用實例上下文apictx.setModuleState
修改目標模塊狀態
changeName = e=> this.ctx.setModuleState('bar', {name: e.target.value})
此文僅僅演示了最最基礎的api用法,幫助你快速上手concent,若是你已是老司機,特別是vue3 one piece
已宣佈正式發佈的這個關頭,若是你很是的不屑一顧這樣笨拙的代碼組織方式,暫先不要急着否認它,且打開官網看一下其餘特性,必定有你喜歡的亮點,包括爲react 量身定製的composition api,模塊級別的reducer
、computed
、watch
、lifecycle
等等新特性,後面的速成會一一提到。
Concent攜帶一整套完整的方案,支持漸進式的開發react組件,即不干擾react自己的開發哲學和組件形態,同時也可以得到巨大的性能收益,這意味着咱們能夠至下而上的增量式的迭代,狀態模塊的劃分,派生數據的管理,事件模型的分類,業務代碼的分隔均可以逐步在開發過程勾勒和剝離出來,其過程是絲滑柔順的,也容許咱們至上而下統籌式的開發,一開始吧全部的領域模型和業務模塊抽象的清清楚楚,同時在迭代過程當中也能很是快速的靈活調整而影響整個項目架構.