mobxjs / mobx-react

React bindings for MobX
https://mobx.js.org/react-integration.html
MIT License
4.85k stars 350 forks source link

mobX with react hooks without provider #873

Closed panda0603 closed 4 years ago

panda0603 commented 4 years ago

Hello, thanks again for the wonderful library.

Upon moving to mobx-react-lite with react hooks, I have two questions.

I have made the following structure as an example:

// animal store
// src/store/animalStore.ts

import {decorate, observable, computed} from 'mobx';

export class AnimalStore {
  animal: string[] = ['cat', 'dog', 'pig'];
  get animalSize() {
    return this.animal.length;
  }
}

decorate(AnimalStore, {
  animal: observable,
  animalSize: computed,
});
// bug store
// src/store/bugStore.ts

import {decorate, observable, computed} from 'mobx';

export class BugStore {
  bug = ['grasshoper', 'cricket', 'ant'];
  get bugSize() {
    return this.bug.length;
  }
}

decorate(BugStore, {
  bug: observable,
  bugSize: computed,
});
// src/store/index.ts

import React from 'react';
import {BugStore} from './bugStore';
import {AnimalStore} from './animalStore';

const storesContext = React.createContext({
  animalStore: new AnimalStore(),
  bugStore: new BugStore(),
});

export const useStores = () => React.useContext(storesContext);
// src/index.tsx

import React from 'react';
import {View, StyleSheet, Text, TouchableOpacity} from 'react-native';
import {observer} from 'mobx-react-lite';
import {useStores} from './store';
import {addAnimal} from './globals/helpers';

const Init: React.FC = () => {
  const {animalStore, bugStore} = useStores();

// using just animalStore for simplicity

  return (
    <View style={styles.container}>
      {animalStore.animal.map((data) => (
        <Text key={data}>{data}</Text>
      ))}
      <TouchableOpacity
        onPress={() => {
          addAnimal('giraffe', animalStore);
        }}>
        <Text>add Animal</Text>
      </TouchableOpacity>
    </View>
  );
};

export default observer(Init);
  1. Is it fine to use mobX without a provider at the top most component?
import React from 'react';
import Init from './src';

const App = () => {
  return <Init />;
};

export default App;

above is my App.tsx, which I have not used any provider, and mobX still seems to work fine. I can call and manipulate store without any problem. Can I not use provider at all? if not, when should we use provider?

  1. Is it fine to manipulate mobX store by passing it down as an argument to a function?
// src/globals/helpers.ts

import {runInAction} from 'mobx';
import {AnimalStore} from '../store/animalStore';

export function addAnimal(item: string, store: AnimalStore) {
  runInAction(() => {
    store.animal.push(item);
  });
}

Let's say I define some utility functions in different folder to add animals to animal Store. Since the function is not a React function component, I cannot call stores using useStores(); Is it okay to pass down stores as an argument and manipulate the stores using runInAction as above? It seems to work fine. Would there be any downsides?

Thanks very much for the help!

danielkcz commented 4 years ago

Please see https://mobx-react.js.org/recipes-context#multiple-global-stores

Anything that works for you is totally fine. Don't try to find some "holy grail" here, there is none. Only bunch of tradeoffs :)

panda0603 commented 4 years ago

Thanks for the reply. Though it works fine in my case, there may be side-effects that I have not encountered yet so it is good to know in advance if it is fine to proceed. I have read the link you have provided, which it says

You could drop the whole Provider dance and set created store as a default value of the createContext. The reference of the store object does not need to change, so it will work in most cases. However, you might still setup a Provider for tests to battle flakiness.

'However, you might still setup a Provider for tests to battle flakiness.' I am not quite sure about what this actually means. When do we 'have' to use providers?

danielkcz commented 4 years ago

Side-effects or tradeoffs are always present in the development and you cannot find "the best" way without them. Sooner you accept it, sooner you will be happy :)

When do we 'have' to use providers?

That depends on so many things. For now, if you don't need a Provider, then don't use it.

panda0603 commented 4 years ago

Let me rephrase the question then, Any reasons 'not' to use providers?

If there aren't any gains, i.e. performance, I would be better of just using providers all the time? Just couple of lines more to add the provider is not a problem at all.

mweststrate commented 4 years ago

This has been discussed several times in the past, for example: https://github.com/mobxjs/mobx-react/issues/553. In general, I recommend not to use things until you know why you are using them. It's often the quickest way to understanding them.

On Wed, Jun 10, 2020 at 11:56 AM Eric notifications@github.com wrote:

Let me rephrase the question then, Any reasons 'not' to use providers?

If there aren't any gains, i.e. performance, I would be better of just using providers all the time? Just couple of lines more to add the provider is not a problem at all.

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/mobxjs/mobx-react/issues/873#issuecomment-641925030, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAN4NBG67GOTEVB3POO4HADRV5RFLANCNFSM4N2B5FAQ .

panda0603 commented 4 years ago

@mweststrate Thanks. Guess I will start using provider once I understand it.

What about question 2? It is okay to alter store in that fashion?

danielkcz commented 4 years ago

If there aren't any gains, i.e. performance, I would be better of just using providers all the time?

There are gains, but until you need them, don't worry about it. Or feel free to spend half a day reading through articles and crawling through discussions. You can start at https://kentcdodds.com/blog/?q=context

Don't optimize until you need it. Any sort of optimization always comes with tradeoffs of code complexity.

mweststrate commented 4 years ago

@panda0603 yeah that is perfectly fine

stale[bot] commented 4 years ago

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.