【问题标题】:Get item from MobX store which is observable object?从 MobX 商店获取可观察对象的项目?
【发布时间】:2018-04-10 03:17:13
【问题描述】:

我正在创建一个简单的 React 单页应用程序,它从 Behance API 提取信息,并将其显示在网站上。

我正在使用 MobX 来存储投资组合项目,以及来自单个项目的模块。

store.js 看起来像:

import { observable } from 'mobx';

class Store {
  constructor() {
    this.storeState = observable({
      portfolioItems: [],
      singleItem: {},
    });
  }
}

export default new Store();

而我的Single.js 看起来像这样

import React, { Component } from 'react';
import { observer } from 'mobx-react';
import { action, toJS } from 'mobx';
import { css } from 'emotion';

import { getItem } from '../../services/api';
import { errorHandler } from '../../services/errorHandler';
import { isInObservableObject } from '../../helpers/isObservable';
import store from '../../state/store';

import Image from '../../components/Image/Image';
import Text from '../../components/Text/Text';

const singleContainer = css`
  display: block;
`;

const backButton = css`
  display: block;
  padding: 20px;
  position: fixed;
  bottom: 50px;
  right: 30px;
  border: 0;
  font-size: 16px;
  cursor: pointer;
  text-transform: uppercase;
  color: #FFFFFF;
  background-color: rgba(0, 0, 0, 0.5);
`;

@observer
class Single extends Component {
  static moduleHandler(module) {
    return (module.sizes) ?
      (
        <Image
          alt="Module image"
          key={module.id}
          src={module.sizes.original}
        />
      ) :
      (
        <Text
          key={module.id}
          type="tertiary"
        >
          {module.text_plain}
        </Text>
      );
  }

  componentWillMount() {
    const {match} = this.props;

    const itemId = match.params.id;

    if (!isInObservableObject(store.storeState.singleItem, itemId)) {
      getItem(itemId).then((result) => {
        if (typeof result.errors !== 'undefined') {
          store.storeState.singleMessage = errorHandler(result.errors);
          return;
        }

        store.storeState.singleItem[itemId] = result.project.modules;
      }).catch((error) => {
        const errorMessage = `Error: ${error}`;
        store.storeState.singleMessage = errorMessage;
      });
    }
  }

  @action.bound handleBack() {
    const {history} = this.props;
    history.goBack();
  }

  render() {
    const { singleItem } = store.storeState;
    const { match } = this.props;

    const itemId = match.params.id;

    const storeObject = toJS(singleItem);
    const iterableItem = storeObject[itemId];

    return (
      <div className={singleContainer}>
        {
          iterableItem.map((module) => (
            this.constructor.moduleHandler(module)
          ))
        }
        <button
          className={backButton}
          onClick={this.handleBack}
        >
          Go Back
        </button>
      </div>
    );
  }
}

export default Single;

我正在使用 php 绕过 CORS 的问题,因此用于获取信息的 api.js 如下所示:

const fetchData = async (endpoint, method, headers, body) => {
  const options = {};

  options.method = method;
  options.headers = headers || {};

  if (typeof body !== 'undefined') {
    options.body = JSON.stringify(body);
  }

  const url = `http://localhost/server.php?project=${endpoint}`;

  return fetch(url, options).then((response) => response.json());
};

export function getItems() {
  const headers = {
    Accept: 'application/json;charset=utf-8',
    'Content-Type': 'application/json;charset=utf-8',
  };

  return fetchData('', 'GET', headers);
}

export function getItem(id) {
  const headers = {
    Accept: 'application/json;charset=utf-8',
    'Content-Type': 'application/json;charset=utf-8',
  };

  return fetchData(id, 'GET', headers);
}

我面临的问题是:如何将数据从存储中取出?对于投资组合项目,这很容易,因为它们存储在一个数组中,我可以映射它们。

但问题是,在singleItem 对象中,我存储了每个项目的模块,并将其存储为可观察对象{$mobx: ObservableObjectAdministration},我可以将其console.log 输出,我可以看到项目我得到了正确的模块

62973499: (17) [{…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}]

但我无法取出这些模块。我试过了

singleItem[itemId]
singleItem.itemId
toJS(singleItem)[itemId] // toJS should convert the observable object to regular one
toJS(singleItem).itemId

没有任何效果。

我以这种方式存储它们是因为我有 20 个左右的项目,所以每个项目都应该是可识别的(它们有一个唯一的 ID,我将其用作键)。

【问题讨论】:

    标签: javascript reactjs mobx


    【解决方案1】:

    回答我自己的问题,因为我找到了解决这个问题的方法。

    首先我更改了商店 - 我的 singleItem 现在是 Map

    import { observable } from 'mobx';
    
    class Store {
      constructor() {
        this.storeState = observable({
          portfolioItems: [],
          singleItem: new Map(),
        });
      }
    }
    
    export default new Store();
    

    接下来,我将componentWillMount 更改为

      componentWillMount() {
        const {match} = this.props;
    
        const itemId = match.params.id;
    
        if (!isInObservableObject(store.storeState.singleItem, itemId)) {
          getItem(itemId).then((result) => {
            if (typeof result.errors !== 'undefined') {
              store.storeState.singleMessage = errorHandler(result.errors);
              return;
            }
    
            store.storeState.singleItem.set(itemId, result.project.modules);
          }).catch((error) => {
            const errorMessage = `Error: ${error}`;
            store.storeState.singleMessage = errorMessage;
          });
        }
      }
    

    然后我偶然发现了这个

    Why componentWillMount is called after rendering?

    我利用它来发挥自己的优势:

    render() {
        const { singleItem } = store.storeState;
        const { match } = this.props;
    
        const itemId = match.params.id;
    
        return (
          <div className={singleContainer}>
            {
              !singleItem.get(itemId) ? (
                <Loader />
              ) : (
                singleItem.get(itemId).map((module) => (
                  this.constructor.moduleHandler(module)
                ))
              )}
            <button
              className={backButton}
              onClick={this.handleBack}
            >
              Go Back
            </button>
          </div>
        );
      }
    

    因此,如果没有获取任何内容,我将展示我的加载器,当它完成时,我将展示该项目。

    作品:D

    【讨论】:

      猜你喜欢
      • 2020-12-01
      • 1970-01-01
      • 2021-12-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-06-25
      • 1970-01-01
      相关资源
      最近更新 更多