简体   繁体   中英

Unidirectional Data Flow in React with MobX

I'm trying to setup a project architecture using MobX and React and was wondering if doing this following would be considered "not bad". I don't want this question to end up being another "this is a matter of personal preference and so this question doesn't belong here... We can all agree that some things really are bad.

So I'm thinking of only having a single Store.js file that looks something like this:

import { observable, action, useStrict } from 'mobx';

useStrict(true);

export const state = observable({
    title: ''
});

export const actions = {
    setTitle: action((title) => {
        state.title = title;
    })
};

Note : that all application state will be in state , there will only be a single store.

I then use state in my root component aka App.js like so:

import React, { Component } from 'react';
import { observer } from 'mobx-react';
import { state } from './Store';
import DisplayTitle from './components/DisplayTitle/DisplayTitle';
import SetTitle from './components/SetTitle/SetTitle';

class App extends Component {

  render() {
    return (
      <div className="App">
        <DisplayTitle title={state.title}/>
        <SetTitle />
      </div>
    );
  }

}

export default observer(App);

I'll obviously have a whole bunch of components in my app, but none of the components will ever read state directly from Store.js . Only my App.js will import the state and pass it down the component tree.

Another note : I'm not so sure anymore why other components can't read the state directly from Store.js ...

This is the case with the DisplayTitle component:

import React, { Component } from 'react';

class DisplayTitle extends Component {
    render () {
        return (
            <h1>{this.props.title}</h1>
        );
    }
}

export default DisplayTitle;

But, even though no other components can directly import state (except App.js ), any component can import actions from Store.js in order to mutate the state .

For example in the SetTitle component:

import React, { Component } from 'react';
import { actions } from './../../Store';

class SetTitle extends Component {

    updateTitle (e) {
        actions.setTitle(e.currentTarget.value);
    }

    render () {
        return (
            <input onChange={this.updateTitle} type='text'/>
        );
    }
}

export default SetTitle;

Are there any flaws or other obvious reasons why this approach wouldn't be the best route to go? I'd love any and all feedback!

you are missing a few things

at root level:

import { Provider } from 'mobx-react'
...

<Provider state={state}>
  <Other stuff />
</Provider>

At component level:

import { inject } from 'mobx-react'

@inject('state')
class Foo ... {
  handleClick(){
    this.props.state.setTitle('foo')
  }
  render(){
    return <div onClick={() => this.handleClick()}>{this.props.state.title}</div>
  }
}

You can stick only the interface actions={actions} in your provider and inject that, ensuring children can call your API methods to mutate state and have it flow from bottom up. Though if you were to mutate it direct, no side effects will happen because all components willReact and update in your render tree - flux is cleaner to reason about.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM