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 91 forks source link

what's the difference between useEffect and autorun #252

Closed surahe closed 4 years ago

surahe commented 4 years ago

I use mobx-react-lite with hooks, while I use setNumber to change local state, or use addNewTodo to change global state, both autorun and useEffect can run.

what's the difference between useEffect and autorun? On what condition will I use useEffect or autorun?

local state

// /src/components/a.jsx

import { observer } from 'mobx-react-lite'
import React, {useState, useEffect} from 'react'
import {autorun} from 'mobx'

export const MyComponent2 = observer(function MyComponent3() {
  const  [number, setNumber] = useState(0)

  autorun(() => {
    console.log(1)
  })

  useEffect(() => {
    console.log(2)
  })

  function setIt(params) {
    setNumber(2)
  }

  return <button onClick={setIt}>button</button>
})

global state

// src/store/index.js

import React, {
  useContext
} from 'react'

import {
  useLocalStore
} from 'mobx-react-lite'

import {
  observable
} from 'mobx'

import {
  ITodo
} from '../interfaces'

const createStore = () => ({
  todos: [] as ITodo[], 
  get finishedTodoCount() {
    return this.todos.filter(todo => todo.finished).length
  },
  get totalCount() {
    return this.todos.length
  },
  finishTodoById(id: number) {
    this.todos.forEach(todo => {
      if (todo.id === id) {
        todo.finished = !todo.finished
      }
    })
  },
  addNewTodo(name: string) {
    this.todos.push(observable({
      id: Math.random(),
      name: name,
      finished: false
    }))
  },
  removeTodoById(id: number) {
    const index = this.todos.findIndex(todo => todo.id === id)
    this.todos.splice(index, 1)
  }
})

type TTodoStore = ReturnType<typeof createStore>

const TodoStoreContext = React.createContext<TTodoStore | null>(null)

const TodoStoreProvider: React.FC = ({ children }) => {
  const store = useLocalStore(createStore)
  return (
    <TodoStoreContext.Provider value={store}>
      {children}
    </TodoStoreContext.Provider>
  )
}

const useTodoStore = () => {
  const store = useContext(TodoStoreContext)
  if (!store) {
    throw new Error('You have forgot to use StoreProvider, shame on you.')
  }
  return store
}

export {
  TodoStoreProvider,
  useTodoStore
}

I read the issue 197,but I still don't know when should I use:

 React.useEffect(() => mobx.autorun(() => {
 }));
danielkcz commented 4 years ago

Generally with autorun you don't need to worry about deps argument to useEffect. Any observables will be identified automatically. Your example is too contrived as it doesn't use any observables in the autorun, so you cannot really see the difference.

See more here: https://mobx-react.js.org/recipes-effects

ynejati commented 4 years ago

@FredyC, this seems like a question and not so much an issue. Maybe it should be closed? @surahe, probably better to use the gitter or stack overflow for any future questions.

danielkcz commented 4 years ago

We don't mind open questions as an issue here, gitter is bad for tracking it later anyway. There is auto close configured and by commenting, you have reset it ;)