如何对observable.map()进行映射/转换
例如,如果我有一个observable.map() of Todos,其中的id是关键:
var Todos = observable.map({
'rf8r4': {id: 'rf8r4', description: 'Get milk'},
'543w4': {id: '543w4', description: 'Code in MobX'},
'099i0': {id: '099i0', description: 'Sleep'}
})如何自动生成UI状态observable.map(),例如包含默认为true的visible属性(注意键对应于上面Todos的键):
ui_state = observable.map({
'rf8r4': {visible: true}, // defaults
'543w4': {visible: false}, // changed to false after some user interaction
'099i0': {visible: true}
})但是,在更改原始Todos映射后,请确保每个Todo的状态保持一致,例如:
Todos.set('grtg6', {id: 'grtg6', description: 'Read StackOverflow'})应该导致(注意543w4的visible属性仍然是false):
ui_state = observable.map({
'rf8r4': {visible: true},
'543w4': {visible: false},
'099i0': {visible: true},
'grtg6': {visible: true} // this is the new one
})我尝试了autorun/createTransformer,但是它最后才被更新,就好像它是一个副作用,所以我不能在React组件中使用ui_state。
我也尝试过不同版本的computed,但是每次都会创建一个新的ui_state,因为如果我在computed函数中使用createTransformer,我会得到一个错误.
谢谢!
发布于 2017-01-31 14:05:18
实际上,我想出了制作map地图的最佳方法。见关于MobX的createTransformer文档。
我在问题中提到,我尝试过createTransformer并遇到了问题。这是因为autorun是用于运行副作用的,因此它在更新所有MobX数据之后运行。这意味着,如果某些MobX数据(例如,'X')同时依赖于map和map的映射,那么当map被更新时,'X‘就会被更新,但是X的另一个依赖项,即映射的映射,因为autorun还没有运行,所以产生的'X’值要么是错误的,要么计算本身就会产生错误。一旦autorun最终运行并更新了map的映射,那么'X‘就必须再次更新。
解决方案是使'X‘只依赖于map的映射,只需在这个map映射中将引用存储在原始map中。
index.js:
import Inferno from 'inferno'
import { Provider } from 'inferno-mobx'
import h from 'inferno-hyperscript';
// Components:
import App from './inferno_components/App.js';
// Stores:
import languages from './stores/LanguagesStore.js';
import ui_state from './stores/LanguageViewState.js';
Inferno.render(
h(Provider, {languages, ui_state}, // the following argument can't be an Array:
h(App)
)
, document.getElementById('main'));
// Make random changes post-render to make sure it re-renders:
languages.set('french', {id: 'french', example: 'Bonjour tout le monde'}); // map already passes the second arg through observable, so we don't need to do it explicitly
languages.get('french').example = 'Merci boucoup';
languages.set('german', {id: 'german', example: 'Gutten tag'});
languages.set('swahili', {id: 'swahili', example: 'Rafiki'});
languages.delete('german');
ui_state.get('english').visible = false;组件/App.js:
// for any component:
import { connect } from 'inferno-mobx'
import h from 'inferno-hyperscript';
// components to be used in this component:
import LanguageView from './LanguageView.js';
// the App:
var App = connect(['ui_state'], function({ui_state}){
return h('div', ui_state.keys().map((language_name) => {
var state = ui_state.get(language_name);
if(state.visible)
return h(LanguageView, {language: state.language});
else
return h('p', 'Sorry, invisible!');
}))
});
export default App;组件/LanguageView.js:
import { connect } from 'inferno-mobx'
import h from 'inferno-hyperscript';
var LanguageView = connect(function({language}){
return h('div', [
h('p', language.id),
h('p', language.example)
]);
});
export default LanguageView;商店/LanguagesStore.js:
import { observable } from 'mobx'
const languages = observable.map({
english: {
id: 'english',
example: 'Hello World'
}
});
export default languages;商店/LanguageViewState.js:
import { observable, createTransformer, intercept } from 'mobx';
import languages from './LanguagesStore.js';
const makeUIStateFromLanguage = createTransformer((language) => {
return {language, visible: true}
});
var ui_state = observable.map({});
// initialize:
languages.forEach((language, language_name) => {
ui_state.set(language_name, makeUIStateFromLanguage(language));
});
// set up automatic updating:
intercept(languages, function(change_object){
if(change_object.type === 'add'){
ui_state.set(change_object.name, makeUIStateFromLanguage(change_object.newValue));
}
else if(change_object.type === 'delete'){
ui_state.delete(change_object.name);
}
return change_object; // for intercept
});
export default ui_state;发布于 2017-01-26 09:07:21
当您在状态中添加一个新条目时,可能很难将一个条目添加到您的ui映射中,但是如果您查看不在ui映射中的条目是可见的,您可以这样做-- 像这样。
const state = observable.map({
'rf8r4': {id: 'rf8r4', description: 'Get milk'},
'543w4': {id: '543w4', description: 'Code in MobX'},
'099i0': {id: '099i0', description: 'Sleep'}
});
@observer
class App extends React.Component {
@observable visible = asMap({
'rf8r4': {visible: false}
});
@computed get visibleState() {
const res = [];
state.forEach(val => {
const item = this.visible.get(val.id);
if (!item || item.visible) {
res.push(val);
}
});
return res;
}
render() {
return <div>
{this.visibleState.map(el =>
<div key={el.id} onClick={this.onClick}> {el.description} </div>
)}
</div>;
}
onClick = () => {
this.visible.set('rf8r4', {visible: true});
};
}https://stackoverflow.com/questions/41867158
复制相似问题