fluxxx
動手實作一個 Isomorphic flux
flux 實作
- Dispatcher
- Store
- Action
Action
一種溝通工具,讓 view 跟 store 約定好要說什麼
避免雞同鴨講
Fluxxx.action({
go: function() {
var flux = this.flux;
flux.getActions().go.dispatch({abc: 123});
}
});
//view
this.flux().getActions().go()
Store
統一資料來源
Single Source of Truth
Fluxxx.store('list', function() {
var flux = this.flux;
var actions = flux.getActions();
var list = [1, 2, 3];
return {
getList: function() {
return list;
},
onPop: function() {
list.pop();
this.emit('change');
},
dehydrate: function() {
return [list];
},
rehydrate: function(state) {
list = state[0];
},
dispatchToken: flux.listenTo('list', function(on) {
on(actions.pop, 'onPop');
}
}
});
Event System
div
input
span
listeners
click、keydown、mosuedown、hover ...
Dispatcher
div
input
span
listeners
click、keydown、mosuedown、hover ...
dispatcher
Problem
- How to render after all stores are populated?
- Singleton issue
- Checksum mismatch
How to render after all stores are populated?
ajax action
How to render after all stores are populated?
var actions = Fluxx.action({
all: function() {
var flux = this.flux;
if(flux.getStore('list').hasInitialized())
return;
return fetch('/api/list.json').then(function(res) {
return res.json();
}).then(function(data) {
flux.getActions().initial(data);
return data;
});
}})
ajax action
How to render after all stores are populated?
action
dispache
ajax action
How to render after all stores are populated?
action
dispache
ajax
solution
收集 promise
要 return action 的 promise
var actions = Fluxx.action({
all: function() {
var flux = this.flux;
return fetch('/api/list.json').then(function(res) {
return res.json();
});
}})
app.get('/', function() {
...
flux.ready(function() {
var html = React.renderToString(app);
res.render('index', {html: html});
});
...
});
Singleton Issue
Server 端禁止共用 dispatcher
每個 request 都要產生 dispatcher
store 跟 action 都要找得到對的 dispatcher
Before
var Dispatcher = require('flux').Dispatcher;
module.exports = new Dispatcher();
//action
var dispatcher = require('dispatcher');
var action = {
all: function() {
dispatcher.dispatch({type: 'all'});
}
};
//store
var dispatcher = require('dispatcher');
var store = assign({}, EventEmitter.prototype, {
onAll: function() {
}
});
dispatcher.register(function(payload) {
if(payload.type == 'all') {
store.onAll(payload)
}
})
After
//action
Fluxx.action({
all: function() {
var flux = this.flux;
}
});
//store
Fluxx.store('list', function() {
var flux = this.flux;
})
app.get('/', function() {
var flux = new Fluxxx();
});
checksum 前端 store 不一致
- dehydrated
- rehydrated
在 store 定義存檔跟還原
Fluxxx.store('list', function() {
var flux = this.flux;
var actions = flux.getActions();
var list = [1, 2, 3];
return {
dehydrate: function() {
return [list];
},
rehydrate: function(state) {
list = state[0];
}
}
});
var data = <?=json_encode($data);?>
後端的資料吐到前端塞回 store 裡面
//server
app.get('/', function() {
var flux = new Fluxxx();
React.renderToString(app);
flux.ready(function() {
var html = React.renderToString(app);
res.render('index', {html: html, dehydratedStr: JSON.stringify(flux.dehydrate())});
});
});
//browser
<script>var __dehydrated = <%- dehydratedStr %></script>
var flux = new Fluxx();
flux.rehydrate(window.__dehydrated);
React.render(<App flux={flux} />, document.getElementById('container'));
參考
總結
用手思考…
具體而微的瞭解 flux
fluxxx
By mlwmlw
fluxxx
- 158