摘要:一個簡潔強大的數據流框架安裝特性上圖為架構圖參考自在其基礎上做了以下簡化和改進功能上集成我們不再需要多寫一個方法去異步獲取數據更多情況下我們將使用讓代碼更加簡潔的使用更加靈活的單實例和多實例使用能很巧妙地實現跨組件通信和通用組件控制邏
Nearly
一個簡潔, 強大的數據流框架; Github
安裝npm install --save nearly-react特性
上圖為 flux 架構圖, Nearly 參考自 flux, 在其基礎上做了以下簡化和改進:
功能上:集成 Promise, 我們不再需要多寫一個 componentDidMount 方法去異步獲取數據, 更多情況下, 我們將使用 stateless component 讓代碼更加簡潔;
Store 的使用更加靈活, Store 的單實例和多實例使用能很巧妙地實現跨組件通信和通用組件控制邏輯的復用;
相比 flux:API 更加簡潔, 在業務中一般只會用到 connect 和 dispatch 方法;
對狀態進行集中管理, 寫法與原始的 React 相似, 學習和遷移成本低;
更輕量, min 后只有 6K;
使用示例import React from "react"; import { render } from "react-dom"; import {connect, dispatch, registerStore} from "nearly-react"; registerStore("counter", { // 必須實現 init 方法, 它將被隱式調用, 作用是初始化 state init() { return { count: 0 }; }, add(getState, step) { return { count: getState().count + step }; } }; let incr = () => dispatch("counter::add", 1); let decr = () => dispatch("counter::add", -1); function Counter(props) { return (API registerStore(storeName, dispatcherSet){props.count}) } let HocCounter = connect("counter", Counter); render(, document.getElementById("root") )
該方法將注冊一個 Store, 需要注意的是該方法必須先 connect 執行, 例:
registerStore("customStore", { // 必須實現 init 方法 init() { return {sum: 0}; }, add(getState, num) { return {sum: getState().sum + num}; } });Dispatcher functions(getState, ...args)
registerStore 接受的第二個參數里的方法即 Dispatcher functions;
Dispatcher function 的第一個參數為 getState 方法, 該方法返回的永遠是當前最新的 state, 其余參數為 dispatch 方法所傳的參數;
對于 Dispatcher function 的返回值:
為普通對象時, 返回值直接 merge 進舊 state;
為 Promise 時, 取 Promise.prototype.then 方法里的參數 merge 進舊 state;
為 null 時, 不 merge, 不觸發 render;
例:
registerStore("counter", { // 必須實現 init 方法, init 中也可以使用 Promise init() { return fetch("./test.json").then(res => res.json()); }, add(getState, step) { return { count: getState().count + step }; }, // 異步增加 addAsync(getState, step) { return new Promise(resolve => { setTimeout(() => { // getState 方法返回的永遠是最新的 state let count = getState().count + step; resolve({count}) }, 1000); }); }, // 不觸發渲染 nothing(getState, step) { return null; } };dispatch(action, ...args)
默認配置的 action 格式為 ${storeName}::${function},
dispatch 會根據 action 映射到相應的 Dispatcher function, 并將 args 作為參數傳入 Dispatcher function, 將其返回的結果提交給 Store, 由 Store 觸發組件更新;
connect(storeName, Component [, PlaceHolder, isPure])該方法會根據 storeName 獲得 Store, 再將 Store, Component 和 PlaceHolder 組合, 返回一個高階組件;
其中, PlaceHolder 為默認展示組件 (可選), 當且僅當 init 返回 Promise 時有效, 在 Component 被插入 dom 之前, 組合后的高階組件會先展示 PlaceHolder 組件, 可用于實現 loading 之類的效果;
但組件過大時, 可以通過設置 isPure 為 true 來提高性能, 當設置 isPure 為 true 時, 只有 dispatch 方法能觸發組件的 render, 我相信這比通過在 shouldComponentUpdate 里寫 shallowEqual 要有效得多;
也可以通過下面的 configure 設置默認的 isPure 為 true;
進階使用 dispatcher(action, ...args)即 dispatch 的高階函數; 例:
dispatch("counter::add", 1); 等同于: dispatcher("counter::add")(1); dispatch("test::testAdd", 1, 2, 3, 4); 等同于: dispatcher("test::testAdd", 1, 2)(3, 4);configure(option)
使用 nearly 進行開發, 我們需要考慮 storeName 重復的情況, 我推薦通過將 storeName 映射文件路徑的方式來避免;
nearly 提供了兩個可供配置的方法: beforeConnect 和 beforeDispatch;
beforeConnect 會在 connect 方法被調用之前調用, 接受的參數為傳入 connect 方法的 storeName; 我們可以用它去加載對應的 JS 文件, 并注冊 Store;
beforeDispatch 會在 dispatch 方法被調用之前調用, 接受的參數為傳入 dispatch 方法的 action;
默認配置如下:
import {registerStore, getStore} from "./store"; let config = { // 默認的 isPure defaultPure: false, // 默認不開啟自動注冊 Store beforeConnect(storeName) { // let store = getStore(storeName); // if (!store) { // let realName = storeName.split("#")[0]; // registerStore(storeName, require(`./actions/${realName}.js`)); // } }, beforeDispatch(action) { let [storeName, dispatcherName] = action.split("::"); let store = getStore(storeName); if (!store) { throw Error(`store "${storeName}" does not exist`); } let dispatcher = store.dispatchers[dispatcherName]; if (!dispatcher) { throw Error(`the module does not export function ${dispatcherName}`); } return {store, dispatcher}; } }
使用示例:
import {configure, getStore, registerStore} from "nearly-react"; configure({ beforeConnect(storeName) { // 配置 beforeConnect 方法, 自動注冊 Store // 當 store 不存在時 // 自動去 actions 目錄下加載 JS 模塊, 并注冊 Store let store = getStore(storeName); if (!store) { let realName = storeName.split("#")[0]; registerStore(storeName, require(`./actions/${realName}.js`)); } } });同一 Store 單實例使用
在業務中我們經常需要跨組件通信, 或者組件間共享數據;
使用 Nearly 我們能很輕易地將兩個不同的組件綁定相同的 Store, 只要傳入 connect 的 storeName 是相同的即可;
例: 簡單的輸入同步顯示
registerStore("vm", { // 必須實現 init 方法, 它將被隱式調用, 作用是初始化 state init() { return { value: "" }; }, change(getState, value) { return { return { value }; }; } }; // /components/Input.js let change = e => dispatch("vm::change", e.target.value); function Input(props) { return } export default connect(Input, "vm"); // /components/Text.js function Text(props) { return{props.value}
} export default connect(Text, "vm");
詳見示例: One-store
同一 Store 多實例使用我們開發通用組件時會需要給同一組件綁定同一 store 的不同實例以復用; 可以通過給 storeName 加上 #id 來區分不同 Store;
// Dialog.js export default function Dialog (props){ return{props.content}} let DialogA = connect(Dialog, "dialog#a"); let DialogB = connect(Dialog, "dialog#b"); // 關閉彈窗 A dispatch("dialog#a::close"); // 關閉彈窗 B dispatch("dialog#b::close");
注意, 當在組件內部使用 dispatch 時, 可以通過 props._storeName 來確定 storeName;
詳見示例: Dialog
示例TodoMVC
Counter
Dialog
One-store
React-SPA-Seed
Tipsnearly-config.js 必須在業務邏輯之前加載;
雖然有 registerStore API, 不過作者還是推薦使用 connect 來隱式注冊 Store, 因為 connect 通過 storeName 映射文件的方式來注冊 Store, 在確保唯一性的同時更容易維護和 debug;
在 Nearly 中對 Promise 的判斷是不準確的 (只要有 then 方法均認為是 Promise 實例) , 一方面是因為 Nearly 中只使用了 then 方法, 另一方面是為了兼容 jQuery.Deferred 等類庫;
歡迎提 issue 或是 pr;
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/83594.html
摘要:下的表格狂想曲前言歡迎大家閱讀從零開始的組件開發之路系列第一篇,表格篇。北京小李中的每一個元素是一列的配置,也是一個對象,至少應該包括如下幾部分表頭該列使用行中的哪個進行顯示易用性與通用性的平衡易用性與通用性互相制衡,但并不是絕對矛盾。 React 下的表格狂想曲 0. 前言 歡迎大家閱讀「從零開始的 React 組件開發之路」系列第一篇,表格篇。本系列的特色是從 需求分析、API 設...
摘要:接上一篇我理想中的狀態管理工具之前說,對于我個人來而言,理想的狀態管理工具只需同時滿足兩個特點簡單易用,并且適合中大型項目完美地支持未能找到一個完美滿足這兩點的,所以我決定自己造了一個叫。把分為和兩類是很好的實踐。 接上一篇:我理想中的狀態管理工具 之前說,對于我個人來而言,理想的狀態管理工具只需同時滿足兩個特點: 簡單易用,并且適合中大型項目 完美地支持 Typescript 未...
摘要:也是一款優秀的響應式框架站點所使用的一套框架為微信服務量身設計的一套框架一組很小的,響應式的組件,你可以在網頁的項目上到處使用一個可定制的文件,使瀏覽器呈現的所有元素,更一致和符合現代標準。 GitHub 值得收藏的前端項目 整理與收集的一些比較優秀github項目,方便自己閱讀,順便分享出來,大家一起學習,本篇文章會持續更新,版權歸原作者所有。歡迎github star與fork 預...
閱讀 1101·2021-11-24 10:24
閱讀 2589·2021-11-22 13:54
閱讀 997·2021-09-24 09:55
閱讀 3600·2019-08-30 15:54
閱讀 1316·2019-08-30 15:44
閱讀 1094·2019-08-30 14:23
閱讀 3201·2019-08-29 13:45
閱讀 1281·2019-08-29 11:19