Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

关于 React 数据层的思考 #14

Open
ustccjw opened this issue Dec 12, 2015 · 0 comments
Open

关于 React 数据层的思考 #14

ustccjw opened this issue Dec 12, 2015 · 0 comments
Labels

Comments

@ustccjw
Copy link
Owner

ustccjw commented Dec 12, 2015

关于 React 数据层的思考

远程数据和本地数据

应用数据按照来源可分为远程数据和本地数据。远程数据一般是前端通过请求远程服务获得,本地数据一般是用来记录用户操作的状态。

数据层需要解决的问题一般是:远程数据的同步组件间数据的同步

远程数据的同步

远程数据需要同步的主要有两种情形:数据实时性比较高用户操作导致了远程数据的更新

远程数据的同步最简单的方法就是:不缓存远程数据,每次都向服务器请求新的数据。很显然,这样的做法能够保证数据的同步。这种方法对一些数据实时性比较高的情形是适用的,但是显然大部分情形下不需要这么实时,我们会缓存远程数据。

那么,我们更关注的是用户操作导致了远程数据更新应该如何同步。比较好的解决方案是:用户发起一些操作请求(POST)后,服务端能够返回需要同步的数据。

远程数据和本地数据的抽象

我们需要一个抽象层,能够对数据缓存进行设置(MAXSIZE, TTL 等等),自动完成远程数据同步。我们希望远程数据模型和本地数据模型接口完全一致,这里就需要提一下 Falcor 这个 JS 库。

Falcor 就是用来帮助你实现数据 Model 抽象的,它的主要特性是:

  • One Model Everywhere;
  • The Data is the API;
  • Bind to the Cloud。

Falcor 的 Model 可以设置初始 cache 和 cache 的一些配置;可以设置数据源 source,数据源只要实现它的 DataSource 接口就好,可以是 HttpDataSource 或者是 WebSocketDataSource。

它的 Model 是 JSON Graph 形式,通过传递 JSON path 来实现对数据的 get/set/call 操作,这就是它的 The Data is the API。存储格式是 JSON Graph(引入了 $ref,可以实现数据引用),解析结果是通用的 JSON 数据格式。

组件间数据的同步

远程数据实现缓存和同步后,远程数据和本地数据对我们来说没有区别,我们需要关心的是组件间数据的同步。这个很好解决,那就是组件共享一个 Model,数据更新后从 Model 重新获取数据再渲染。关于 Model 的结构类型,图形结构(ex: JSON Graph)要优于树形结构(ex: Redux reducer tree),图形结构可以很自然的定义实体,实现实体共享(引用)。

利用 Falcor 来抽象应用 Model

我们可以把 Model 分为:dataModel 和 uiModel。dataModel 关联远程服务数据源,uiModel 是用来存储本地 UI 操作的数据。用 Falcor 来创建和管理 dataModel 和 uiModel。需要注意:由于对远程数据源的抽象,我们对 Model 的操作(get/set/call)都是基于 Observable/Promise 的异步操作。

异步 Model 和数据流

我们的 Model 数据操作现在是异步的了,可是 React 组件的渲染机制是同步的,为此,我们可以使用 react-router 的 async-props 扩展来实现异步 props。

我们不能把所有的组件都扩展成 async props,否则性能上肯定吃不消,也不利于优化,而且也容易导致数据流混乱。一种可能的方式是:以 route component 为数据获取入口,在 route component 处使用 async props 来获取数据。route component 的子组件使用的还是同步 props 数据。

执行数据更新操作后,如何刷新应用?那就是重新获取当前路径所有的 route components 的 async props ,然后再重新渲染(执行一次 reload 操作)。这样我们不需要知道需要更新哪些数据,这个由 set/call 操作的返回的 JSON Graph 来更新,我们只要在 set/call 操作(或者一组 set/call 操作)后执行 reload (更新当前路径所有的 route components 的 async props 再重新渲染)。

服务器端渲染并初始化 Model

React 应用实现服务器端渲染很简单,我们可以把渲染完成后的 Model Cache 通过 js 注入传给前端用来作为前端初始化 Model 的 Chache。

const dataCache = safeScript(JSON.stringify(dataModel.getCache()))
scriptTag = `<script>
    window.dataCache=${dataCache}
</script>`
export const dataModel = new falcor.Model({
    source: new HttpDataSource(url),
})
export const uiModel = new falcor.Model({
    cache: {
        articleList: {
            page: 1,
        },
    },
})
if (global.dataCache) {
    dataModel.setCache(global.dataCache)
}

具体的实验可参考:https://github.com/ustccjw/tech-blog

@ustccjw ustccjw added the blog label Dec 12, 2015
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

1 participant