web-dev-qa-db-ja.com

ES6クラスを使用するときにmobx.js @observerで状態を小道具に接続する方法は?

React and React Router。

@observer class Module1 extends React.Component {

  constructor (props) {
    super(props);
    //...
  }

  componentWillMount(){
    //...
  }

  method(){
    //...
  }

  otherMethod(){
    //...
  }

  render() {
    return (
       <ChildComp bars={this.props.bars}/>}
    );
  }
}

そして、このような状態を取りましょう

state = observable({
  module1:{
    bars:{
      //...
    }
  },
  module2:{
    foos:{
      //...
    }
  }
})

Module1コンポーネントは次のようにロードされます。

//index.js
render(
      <Router history={browserHistory}>
        <Route path="/" component={App}>
          <Route path='/map' component={Module1} >
            <Route path="/entity/:id" component={SubModule}/>
          </Route>
          <Route path='/map' component={Module2} >
        </Route>
      </Router>,
      document.getElementById('render-target')
    );

小道具module1.barsをModule1コンポーネントに渡すにはどうすればよいですか? reduxでは<provider>redux-connectを使用しますが、Mobx.jsではこれに少し迷います。

20
dagatsoin

まず、MobX、Reactおよびreact-routerを使用してルーティングを行う簡単なサンプルアプリを次に示します。 https://github.com/contacts-mvc/mobx-react-TypeScript

一般的に、個人的には、関連するすべてのストアをコンポーネントに明示的な小道具として明示的に渡すのが好きです。ただし、 Ryan のようなパッケージを使用して、React Redux接続と同様のコンテキストメカニズムを使用してストアをコンポーネントに渡すこともできます(こちらを参照してください app 例)。

コンポーネントにストアを作成したら、ComponentWillMountでルーティングパラメーターを解析し、それに応じてストアを更新します。

それは基本的にすべてであるはずです:)しかし、私が答えていないものを聞かせたら教えてください。

10
mweststrate

1週間前、reactmobxで新しいプロジェクトを開始しました。そして、あなたと同じ問題に直面しました。周りを見て、reactのcontextを使用するのが最良の方法であることがわかりました。方法は次のとおりです。

ストア:stores/Auth.js

import { get, post } from 'axios';
import { observable, computed } from 'mobx';
import jwt from 'jsonwebtoken';
import singleton from 'singleton';

import Storage from '../services/Storage';

class Auth extends singleton {
  @observable user = null;
  @computed get isLoggedIn() {
    return !!this.user;
  }

  constructor() {
    super();

    const token = Storage.get('token');

    if (token) {
      this.user = jwt.verify(token, JWT_SECRET);
    }
  }

  login(username, password) {
    return post('/api/auth/login', {
      username, password
    })
    .then((res) => {
      this.user = res.data.user;
      Storage.set('token', res.data.token);
      return res;
    });
  }

  logout() {
    Storage.remove('token');
    return get('/api/auth/logout');
  }
}

export default Auth.get();

注:ストアはリアクションコンポーネントの外部で使用できるため、シングルトンを使用してインスタンスが1つだけであることを確認しています。 routes.js

ルート:routes.js

import React from 'react';
import { Route, IndexRoute } from 'react-router';

import App from './App';
import Login from './Login/Login';
import Admin from './Admin/Admin';
import Dashboard from './Admin/views/Dashboard';
import Auth from './stores/Auth'; // note: we can use the same store here..

function authRequired(nextState, replace) {
  if (!Auth.isLoggedIn) {
    replace('/login');
  }
}

export default (
  <Route name="root" path="/" component={App}>
    <Route name="login" path="login" component={Login} />
    <Route name="admin" path="admin" onEnter={authRequired} component={Admin}>
      <IndexRoute name="dashboard" component={Dashboard} />
    </Route>
  </Route>
);

主なコンポーネント:App.js

// App.js
import React, { Component } from 'react';
import Auth from './stores/Auth';

export default class App extends Component {

  static contextTypes = {
    router: React.PropTypes.object.isRequired
  };

  static childContextTypes = {
    store: React.PropTypes.object
  };

  getChildContext() {
    /**
     * Register stores to be passed down to components
     */
    return {
      store: {
        auth: Auth
      }
    };
  }

  componentWillMount() {
    if (!Auth.isLoggedIn) {
      this.context.router.Push('/login');
    }
  }

  render() {
    return this.props.children;
  }
}

最後に、ストアを使用するコンポーネント:Login.js

import React, { Component } from 'react';
import { observer } from 'mobx-react';

@observer
export default class Login extends Component {

  static contextTypes = {
    router: React.PropTypes.object.isRequired,
    store: React.PropTypes.object.isRequired
  };

  onSubmit(e) {
    const { auth } = this.context.store; // this is our 'Auth' store, same observable instance used by the `routes.js`

    auth.login(this.refs.username.value, this.refs.password.value)
      .then(() => {
        if (auth.isLoggedIn) this.context.router.Push('/admin');
      })
      .catch((err) => {
        console.log(err);
      });

    e.preventDefault();
  }

  render() {
    return (
      <div className="login__form">
        <h2>Login</h2>
        <form onSubmit={this.onSubmit.bind(this)}>
          <input type="text" ref="username" name="username" placeholder="Username" />
          <input type="password" ref="password" name="password" placeholder="Password" />
          <button type="submit">Login</button>
        </form>
      </div>
    );
  }
}

新しいストアを宣言し、App.jsgetChildContextに追加し、特定のストアが必要なときはいつでも、コンポーネントのstorecontextTypes依存関係を宣言できます。 this.contextから取得します。

observableをpropとして渡すことは必須ではないことに気づきました。@observerデコレータを使用し、observableコンポーネントの値、mobxmobx-reactは魔法を使います。

ところでreduxの<Provider store={myStore}><App /></Provider>App.jsで説明したのと同じことをします。 https://egghead.io/lessons/javascript-redux-passing-the-store-down-implicitly-via-context

参照:

42
thaerlabs

mobx-react は、(実験-これを書いている時点で)Provider(コンポーネント)およびinject(高次コンポーネント)を提供して、コンポーネント階層にプロパティを渡します。未満。

上記から、Providerコンポーネントを使用して、すべての関連情報を渡すことができます。フードの下でReactコンテキストが使用されます。

import { Provider } from 'mobx-react';
...
import oneStore from './stores/oneStore';
import anotherStore from './stores/anotherStore';

const stores = { oneStore, anotherStore };

ReactDOM.render(
  <Provider { ...stores }>
    <Router history={browserHistory}>
      <Route path="/" component={App}>
        <Route path="/" component={SomeComponent} />
      </Route>
    </Router>
  </Provider>,
  document.getElementById('app')
);

SomeComponentでは、inject HOCを使用して、渡されたプロパティを取得できます。

import { observer, inject } from 'mobx-react';
...

const SomeComponent = inject('oneStore', 'anotherStore')(observer(({ oneStore, anotherStore }) => {
  return <div>{oneStore.someProp}{anotherStore.someOtherProp}</div>;
}))

export default SomeComponent;

[免責事項: MobX React:Reactでの状態管理の簡略化 で説明しました。SoundCloudAPIを消費する 最小限の定型アプリケーション を確認できます。]

15
Robin Wieruch

react-tunnel を見てください。 Providerコンポーネントとinjectデコレータ(reduxのconnectのように機能します)を提供します。

4
kuuup