反应

时间:2018-06-12 20:13:05

标签: javascript reactjs mobx mobx-react

我想要实现的目标

我有一个商店对象,我想用其他对象的实例填充其中一个属性(这是一个空数组)。我希望我的一个反应组件在部分提到的数组实例发生更改时自动更新。

我的问题是什么

通过注销这个构造的商店对象的值,我可以看到浏览器控制台中的更改,但是当它的值发生变化时,它不会在react组件中自动更新。

所以我想得到一些提示,例如如何实现这样的解决方案。

详细

我的项目

我想创建一个名为 Session 的MobX商店,它将存储我的反应webapp所需的所有内容。 此webapp将是一个文档处理工具,因此在创建新文档或加载现有文档后,我想将文档对象添加到会话(进入名为的对象数组中)文件)。 更多详细信息:文档由一个或多个部分组成。因此,使用WYSIWYG编辑器,我会在每次内容更改时将其内容添加到给定的部分。

问题

我可以在会话中添加新的文档,我也可以更新部分(我可以在控制台中注销部分的值),但是使用会话引用此文档和反应组件中的部分,当更改节值时,它不会更新其状态。 根据我在我的示例中的理解,当部分的值发生更改时,文档的引用不会更改,因此它不会触发MobX做出反应。

到目前为止我找到了什么

我开始深入挖掘黑暗的网页并找到this文章。 所以我开始感到兴奋,因为 asStructure (或 asMap )似乎解决了这个问题,但看起来不推荐使用MobX中的 asStructure 。 然后我找到了这个issue线程,其中提到了一个名为 observable.structurallyCompare 的东西。但是我再次在MobX文档中没有发现这一点,所以我很困惑如何实现它。

所以我再次陷入困境,不知道如何解决这个问题。

代码摘录自我的项目

这是我引用主反应组件中提到的Session值的方式:

import userSession from '../client/Session';
import {observer} from 'mobx-react';

@observer class App extends React.Component {
...

render() {

  return (
    ...
    <div>{JSON.stringify(userSession.documents[0].content.sections)}</div>

  ...

这是我更新编辑器反应组件部分的方法:

import userSession from '../../client/Session';
...

handleChange(value,arg2,arg3,arg4) {
  this.setState({ content: value, delta: arg4.getHTML()});
  userSession.documents[0].updateSectionContent(this.props.id, this.state.delta);
  }
}

...

Session.js摘录:

class Session {
  constructor(){
    extendObservable(this, {
      user: {
      },
      layout: {
      },
      documents: []
    })

    //current hack to add an empty Document to Session
    this.documents.push(new Document());
  }

  //yadayadayada...

  @action addNewSection() {
    userSession.documents[0].content.sections.push({
            type: "editor",
            id: userSession.documents[0].getNextSectionID(),
            editable: true,
            content: "",
            placeholder: "type here to add new section..."
    });
  }
}

var userSession = window.userSession = new Session();
export default userSession;

Document.js

import {extendObservable, computed, action} from "mobx";
import userSession from "./Session";

class Document {
  constructor(doc = null) {
    if (doc == null) {
      console.log("doc - no init value provided");
      extendObservable(this,{
        labels: {
          title: "title",
          description: "description",
          owners: ["guest"]
        },
        content: {
          sections: [
            {
              type: "editor",
              id: "sec1",
              editable: true,
              placeholder: "this is where the magic happens"
            },
          ]
        }
      })

    } else {
      console.log("doc - init values provided: ");
      extendObservable(this,{
        labels: doc.labels,
        content: doc.content
      });
    }
  }

  getNextSectionID(){
    return `sec${this.content.sections.length}`;
  }

  @action updateSectionContent(sectionID, delta) {
    console.log("doc - looking for section " + sectionID + " to update with this: " + delta);
    let index = this.content.sections.findIndex(
      section => section.id === sectionID
    );
    userSession.documents[0].content.sections[index].content = delta;

  }
}

export default Document;

Ps。:atm片刻我不记得为什么我可以观察文件属性,但由于某种原因它是必要的。

1 个答案:

答案 0 :(得分:0)

不幸的是,您正在使用React以错误的方式实现mobx。为了使其更易于理解,我建议您研究observer提供的HOC mobx-react的实现。

基本上,这个HOC所做的是将你的组件包装在另一个实现shouldComponentUpdate的React组件中,该组件检查render函数内引用的 props 何时发生变化,并触发重新渲染。要使React组件对mobx商店中的更改有反应,您需要将商店数据作为props传递给它们,或者采用React传统方式,或者通过inject HOC {{1}提供。

当您的代码未对商店中的更改做出反应时,问题是因为您导入商店并直接在组件中使用它们,mobx-react无法检测到这种方式的更改。

要使其成为被动的,而不是导入它并直接在mobx-react组件中使用它,您可以将商店作为道具传递如下:

App

然后在使用时将商店传递给@observer class App extends React.Component { ... render() { return ( ... <div>{this.props.sections}</div> ...); } }

App

您还可以在此处查看如何使用<App sections={userSession.documents[0].content.sections} /> https://github.com/mobxjs/mobx-react

只是一个建议:在直接跳到某些inject之前,尝试坚持图书馆作者推荐的基本标准方式,并了解它的工作原理,在获得核心思想后,您可以考虑其他选项