Nearly 是一个轻量, 高效, 简洁的数据流框架;

网友投稿 582 2022-10-30

Nearly 是一个轻量, 高效, 简洁的数据流框架;

Nearly 是一个轻量, 高效, 简洁的数据流框架;

Grax

一个简洁, 强大的数据流框架;

安装

npm install --save grax-react

依赖

Grax 依赖 Promise, 对需要兼容旧版本浏览器的场景, 需要使用 polyfill;

特性

上图为 flux 架构图, Grax 参考自 flux, 在其基础上做了以下简化和改进:

功能上:

我们不再需要在 componentDidMount 里去异步获取数据来渲染组件, 更多情况下, 我们将使用 stateless component 来使代码更加简洁;我们可以通过返回一个 Promise 来表示一个异步的 Action, 更加简洁;

相比 flux:

API 更加简洁, 在业务中一般只会用到 connect 和 dispatch 方法;对状态进行集中管理, 写法与原始的 React 相似, 学习和迁移成本低;友好的服务器端渲染支持;更轻量, 压缩后文件大小只有 6K;

使用示例

import React from 'react';import {render} from 'react-dom';import {connect, dispatch, registerStore} from 'grax-react';registerStore('vm', { // 必须实现 init 方法, 它将被隐式调用, 作用是初始化 state init() { return { value: '' }; }, change(getState, value) { return { value }; }};let change = (val) => dispatch('vm.change', val);function Input(props) { return }function Text(props) { return

{props.store.vm.value}

}let GInput = connect('vm', Input);let GText = connect('vm', Text);render(
, document.getElementById('root'))

API

registerStore(storeName, dispatcherFunctions)

该方法将注册一个 Store, 需要注意的是该方法必须先 connect 执行, 例:

registerStore('customStore', { // 必须实现 init 方法 init() { return {count: 0}; }, // Dispatcher function add(getState, num) { return {count: getState().count + num}; }});

Dispatcher functions(getState, ...args)

registerStore 接受的第二个参数里的方法即 Dispatcher functions; Dispatcher function 的第一个参数为 getState 方法, 该方法返回的永远是当前最新的 state, 其余参数为 dispatch 方法所传的参数;

对于 Dispatcher function 的返回值:

为普通对象时, 返回值直接 merge 进旧 state;为 Promise 时, 取 resolve 的值 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}.${dispatcherName},

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

connect 是一个高阶组件, 其将 Component 包裹后返回一个全新的组件;

storeNames 可以是字符串或字符串数组, 当一个组件需要绑定多个 store 时可传入一个字符串数组;Component 是需要被绑定 store 的组件, 绑定后, Component 的 props 会被注入 storeNames 和 store 属性, 详见文档的第一个例子;PlaceHolder 为默认展示组件 (可选), 默认值为 false, 当且仅当 store 的 init 返回 Promise 时有效, 在 Component 被插入 dom 之前, 会先展示 PlaceHolder 组件, 可用于实现 loading 之类的效果;isPure 是一个用于性能优化的配置, 默认值为 false, 当设置为 true 时, 父组件的 render 将不会触发该组件的 render, 只有该组件所connect 的 store 里的 dispatch 方法能触发该组件的 render, 我相信这比通过在 shouldComponentUpdate 里写 shallowEqual 要高效和精准得多;

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)

grax 提供了以下可供配置的参数;

defaultPure, 默认值为 false, 设置为 true 时所有 connect 方法的 isPure 参数都会默认为 true;beforeConnect 会在 connect 方法被调用之前调用, 接受的参数为传入 connect 方法的 storeName;beforeDispatch 会在 dispatch 方法被调用之前调用, 接受的参数为传入 dispatch 方法的 action;

注意 configure 必须在业务逻辑之前运行, 否则不生效;

例:

import {configure} from 'grax-react';configure({ defaultPure: true, beforeConnect(storeNames) {}, beforeDispatch(action) {}});

服务器端渲染

先看一个简单的例子, 详情可参考示例 Counter-ssr;

import React from 'react';import {renderToString} from 'react-dom/server';import {ContextProvider, prepare} from 'grax-react';import Counter from './Components/Counter';// ContextProvider 仅在服务器端渲染时需要function ServerApp (props) { return ( );}export function renderServerApp () { return prepare(['counter']).then(data => { // data === { counter: { count: 0 } } return renderToString(); });}

prepare(storeNames)

storeNames 可以是字符串或字符串数组, 即本次渲染所需的 store, prepare 会根据 storeNames 找到相应的 store, 并运行 init 方法, 所以 storeNames 必须先经过 registerStore;该方法返回一个 Promise, 在后端, Promise 所 resolve 的对象需传进 ContextProvider, 前端则需要把该对象写入 window.__GRAX_STATE__ 来同步前端端的数据;

示例

TodoMVCCounterCounter-ssrDialogMVVM

Tips

推荐在 beforeConnect 中通过传入的 storeName 映射文件名, 动态 require 来 registerStore, 这样在保证 storeName 唯一性的同时会更加直观和好维护;在 Grax 中对 Promise 的判断是不准确的 (只要有 then 方法均认为是 Promise 实例) , 一方面是因为 Grax 中只使用了 then 方法, 另一方面是为了兼容 jQuery.Deferred 等类库;欢迎提 issue 或是 pr;

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:使用自定义注解实现redisson分布式锁
下一篇:hdu5033 最大仰望角
相关文章

 发表评论

暂时没有评论,来抢沙发吧~