mobxjs / mobx-react-lite

Lightweight React bindings for MobX based on React 16.8 and Hooks
https://mobx.js.org/react-integration.html
MIT License
2.13k stars 90 forks source link

how to externalize stores #232

Closed scottschafer closed 4 years ago

scottschafer commented 4 years ago

I'm new to React Hooks. So I can write the following within App.tsx, but I really want to put the creation of stores in separate files. I can't figure out how to do that - everything I've tried results in one error or another.

Working code:

export const App = observer(() => {

  const todoStore = {
    todos: [
      { id: 1, text: 'Buy eggs', completed: true },
      { id: 2, text: 'Write a post', completed: false }
    ],
    toggleTodo(index: number) {
      store.todos[index].completed = !store.todos[index].completed
    },
    get remainingTodos() {
      return store.todos.filter((t: Todo) => !t.completed).length
    }
  };
  const store = useObservable(todoStore);

What I'd like to do is something like this:

export const App = observer(() => {
   const store = useCreateTodoStore();

and in a separate file:

export function useCreateTodoStore() {
  const todoStore = {
    todos: [
      { id: 1, text: 'Buy eggs', completed: true },
      { id: 2, text: 'Write a post', completed: false }
    ],
    toggleTodo(index: number) {
      store.todos[index].completed = !store.todos[index].completed
    },
    get remainingTodos() {
      return store.todos.filter((t: Todo) => !t.completed).length
    }
  };

  const store = useAsObservableSource(todoStore);
  return store;
}

But when I try this I get errors about initialization order.

How can I accomplish this? Thanks.

danielkcz commented 4 years ago

Why useAsObservableSource? You need useLocalStore instead.

jeremy-coleman commented 4 years ago

@FredyC almost all of the examples are using observables created inside the components, which are practically useless to real world use cases, which im sure he read, I think it would be beneficial emphasize use of Idiomatic mobx, just wrap in observer and use a store or props that will reference a store. I think the docs could just show that 10x , and itd be more impactful to the people reading them

scottschafer commented 4 years ago

Thanks to both of you and sorry for not replying sooner.

Yeah, I found this a bit confusing. I want my stores to be kept separate from components and to be able to interact directly with each other. Some examples would be helpful.

But I think I can just create my stores manually the way I'm used to (with @observable / @computed / @action decorations) and use return useObserver(() => (in my functional components.

Seems to work anyway. Any issues with that approach?

jeremy-coleman commented 4 years ago

Just wrap your component in observer like it has always been done . if u look at the source code, u can see it uses use observer and also wraps it into react.memo . You likely will never need to use anything else

scottschafer commented 4 years ago

Sorry for not reading the documentation more fully. This makes sense.