首页
学习
活动
专区
圈层
工具
发布

MobX地图
EN

Stack Overflow用户
提问于 2017-01-26 04:58:42
回答 2查看 3.8K关注 0票数 1

如何对observable.map()进行映射/转换

例如,如果我有一个observable.map() of Todos,其中的id是关键:

代码语言:javascript
复制
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(),例如包含默认为truevisible属性(注意键对应于上面Todos的键):

代码语言:javascript
复制
ui_state = observable.map({
    'rf8r4': {visible: true}, // defaults
    '543w4': {visible: false}, // changed to false after some user interaction
    '099i0': {visible: true}
})

但是,在更改原始Todos映射后,请确保每个Todo的状态保持一致,例如:

代码语言:javascript
复制
Todos.set('grtg6', {id: 'grtg6', description: 'Read StackOverflow'})

应该导致(注意543w4visible属性仍然是false):

代码语言:javascript
复制
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,我会得到一个错误.

谢谢!

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2017-01-31 14:05:18

实际上,我想出了制作map地图的最佳方法。见关于MobX的createTransformer文档

我在问题中提到,我尝试过createTransformer并遇到了问题。这是因为autorun是用于运行副作用的,因此它在更新所有MobX数据之后运行。这意味着,如果某些MobX数据(例如,'X')同时依赖于mapmap的映射,那么当map被更新时,'X‘就会被更新,但是X的另一个依赖项,即映射的映射,因为autorun还没有运行,所以产生的'X’值要么是错误的,要么计算本身就会产生错误。一旦autorun最终运行并更新了map的映射,那么'X‘就必须再次更新。

解决方案是使'X‘只依赖于map的映射,只需在这个map映射中将引用存储在原始map中。

index.js:

代码语言:javascript
复制
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:

代码语言:javascript
复制
// 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:

代码语言:javascript
复制
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:

代码语言:javascript
复制
import { observable } from 'mobx'

const languages = observable.map({
    english: {
        id: 'english',
        example: 'Hello World'
        }
    });

export default languages;

商店/LanguageViewState.js:

代码语言:javascript
复制
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;
票数 1
EN

Stack Overflow用户

发布于 2017-01-26 09:07:21

当您在状态中添加一个新条目时,可能很难将一个条目添加到您的ui映射中,但是如果您查看不在ui映射中的条目是可见的,您可以这样做-- 像这样

代码语言:javascript
复制
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});
  };
}
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/41867158

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档