成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

更簡潔易用的 react 數(shù)據(jù)流 nearly-react

xushaojieaaa / 1898人閱讀

摘要:一個簡潔強大的數(shù)據(jù)流框架安裝特性上圖為架構(gòu)圖參考自在其基礎(chǔ)上做了以下簡化和改進功能上集成我們不再需要多寫一個方法去異步獲取數(shù)據(jù)更多情況下我們將使用讓代碼更加簡潔的使用更加靈活的單實例和多實例使用能很巧妙地實現(xiàn)跨組件通信和通用組件控制邏

Nearly

一個簡潔, 強大的數(shù)據(jù)流框架; Github

安裝
npm install --save nearly-react
特性

上圖為 flux 架構(gòu)圖, Nearly 參考自 flux, 在其基礎(chǔ)上做了以下簡化和改進:

功能上:

集成 Promise, 我們不再需要多寫一個 componentDidMount 方法去異步獲取數(shù)據(jù), 更多情況下, 我們將使用 stateless component 讓代碼更加簡潔;

Store 的使用更加靈活, Store 的單實例和多實例使用能很巧妙地實現(xiàn)跨組件通信和通用組件控制邏輯的復(fù)用;

相比 flux:

API 更加簡潔, 在業(yè)務(wù)中一般只會用到 connectdispatch 方法;

對狀態(tài)進行集中管理, 寫法與原始的 React 相似, 學(xué)習(xí)和遷移成本低;

更輕量, min 后只有 6K;

使用示例
import React from "react";
import { render } from "react-dom";
import {connect, dispatch, registerStore} from "nearly-react";

registerStore("counter", {
    // 必須實現(xiàn) init 方法, 它將被隱式調(diào)用, 作用是初始化 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 (
        
{props.count}
) } let HocCounter = connect("counter", Counter); render( , document.getElementById("root") )
API registerStore(storeName, dispatcherSet)

該方法將注冊一個 Store, 需要注意的是該方法必須先 connect 執(zhí)行, 例:

registerStore("customStore", {
    // 必須實現(xiàn) init 方法
    init() {
        return {sum: 0};
    },
    add(getState, num) {
        return {sum: getState().sum + num};
    }
});
Dispatcher functions(getState, ...args)

registerStore 接受的第二個參數(shù)里的方法即 Dispatcher functions;
Dispatcher function 的第一個參數(shù)為 getState 方法, 該方法返回的永遠是當前最新的 state, 其余參數(shù)為 dispatch 方法所傳的參數(shù);

對于 Dispatcher function 的返回值:

為普通對象時, 返回值直接 merge 進舊 state;

Promise 時, 取 Promise.prototype.then 方法里的參數(shù) merge 進舊 state;

null 時, 不 merge, 不觸發(fā) render;

例:

registerStore("counter", {
    // 必須實現(xiàn) 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);
        });
    },

    // 不觸發(fā)渲染
    nothing(getState, step) {
        return null;
    }
};
dispatch(action, ...args)

默認配置的 action 格式為 ${storeName}::${function},

dispatch 會根據(jù) action 映射到相應(yīng)的 Dispatcher function, 并將 args 作為參數(shù)傳入 Dispatcher function, 將其返回的結(jié)果提交給 Store, 由 Store 觸發(fā)組件更新;

connect(storeName, Component [, PlaceHolder, isPure])

該方法會根據(jù) storeName 獲得 Store, 再將 Store, ComponentPlaceHolder 組合, 返回一個高階組件;

其中, PlaceHolder 為默認展示組件 (可選), 當且僅當 init 返回 Promise 時有效, 在 Component 被插入 dom 之前, 組合后的高階組件會先展示 PlaceHolder 組件, 可用于實現(xiàn) loading 之類的效果;

但組件過大時, 可以通過設(shè)置 isPure 為 true 來提高性能, 當設(shè)置 isPure 為 true 時, 只有 dispatch 方法能觸發(fā)組件的 render, 我相信這比通過在 shouldComponentUpdate 里寫 shallowEqual 要有效得多;

也可以通過下面的 configure 設(shè)置默認的 isPure 為 true;

進階使用 dispatcher(action, ...args)

dispatch 的高階函數(shù); 例:

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 進行開發(fā), 我們需要考慮 storeName 重復(fù)的情況, 我推薦通過將 storeName 映射文件路徑的方式來避免;

nearly 提供了兩個可供配置的方法: beforeConnectbeforeDispatch;

beforeConnect 會在 connect 方法被調(diào)用之前調(diào)用, 接受的參數(shù)為傳入 connect 方法的 storeName; 我們可以用它去加載對應(yīng)的 JS 文件, 并注冊 Store;

beforeDispatch 會在 dispatch 方法被調(diào)用之前調(diào)用, 接受的參數(shù)為傳入 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 單實例使用

在業(yè)務(wù)中我們經(jīng)常需要跨組件通信, 或者組件間共享數(shù)據(jù);

使用 Nearly 我們能很輕易地將兩個不同的組件綁定相同的 Store, 只要傳入 connectstoreName 是相同的即可;
例: 簡單的輸入同步顯示

registerStore("vm", {
    // 必須實現(xiàn) init 方法, 它將被隱式調(diào)用, 作用是初始化 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 多實例使用

我們開發(fā)通用組件時會需要給同一組件綁定同一 store 的不同實例以復(fù)用; 可以通過給 storeName 加上 #id 來區(qū)分不同 Store;

// Dialog.js
export default function Dialog (props){
    return 
{props.content}
} let DialogA = connect(Dialog, "dialog#a"); let DialogB = connect(Dialog, "dialog#b"); // 關(guān)閉彈窗 A dispatch("dialog#a::close"); // 關(guān)閉彈窗 B dispatch("dialog#b::close");

注意, 當在組件內(nèi)部使用 dispatch 時, 可以通過 props._storeName 來確定 storeName;

詳見示例: Dialog

示例

TodoMVC

Counter

Dialog

One-store

React-SPA-Seed

Tips

nearly-config.js 必須在業(yè)務(wù)邏輯之前加載;

雖然有 registerStore API, 不過作者還是推薦使用 connect 來隱式注冊 Store, 因為 connect 通過 storeName 映射文件的方式來注冊 Store, 在確保唯一性的同時更容易維護和 debug;

在 Nearly 中對 Promise 的判斷是不準確的 (只要有 then 方法均認為是 Promise 實例) , 一方面是因為 Nearly 中只使用了 then 方法, 另一方面是為了兼容 jQuery.Deferred 等類庫;

歡迎提 issue 或是 pr;

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/83594.html

相關(guān)文章

  • 從零開始 React 組件開發(fā)之路 (一):表格篇

    摘要:下的表格狂想曲前言歡迎大家閱讀從零開始的組件開發(fā)之路系列第一篇,表格篇。北京小李中的每一個元素是一列的配置,也是一個對象,至少應(yīng)該包括如下幾部分表頭該列使用行中的哪個進行顯示易用性與通用性的平衡易用性與通用性互相制衡,但并不是絕對矛盾。 React 下的表格狂想曲 0. 前言 歡迎大家閱讀「從零開始的 React 組件開發(fā)之路」系列第一篇,表格篇。本系列的特色是從 需求分析、API 設(shè)...

    DesGemini 評論0 收藏0
  • 可能是基于 Hooks 和 Typescript 最好狀態(tài)管理工具

    摘要:接上一篇我理想中的狀態(tài)管理工具之前說,對于我個人來而言,理想的狀態(tài)管理工具只需同時滿足兩個特點簡單易用,并且適合中大型項目完美地支持未能找到一個完美滿足這兩點的,所以我決定自己造了一個叫。把分為和兩類是很好的實踐。 接上一篇:我理想中的狀態(tài)管理工具 之前說,對于我個人來而言,理想的狀態(tài)管理工具只需同時滿足兩個特點: 簡單易用,并且適合中大型項目 完美地支持 Typescript 未...

    derek_334892 評論0 收藏0
  • GitHub 值得收藏前端項目[每月新...]

    摘要:也是一款優(yōu)秀的響應(yīng)式框架站點所使用的一套框架為微信服務(wù)量身設(shè)計的一套框架一組很小的,響應(yīng)式的組件,你可以在網(wǎng)頁的項目上到處使用一個可定制的文件,使瀏覽器呈現(xiàn)的所有元素,更一致和符合現(xiàn)代標準。 GitHub 值得收藏的前端項目 整理與收集的一些比較優(yōu)秀github項目,方便自己閱讀,順便分享出來,大家一起學(xué)習(xí),本篇文章會持續(xù)更新,版權(quán)歸原作者所有。歡迎github star與fork 預(yù)...

    maxmin 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<