Зачем mobx нужны действия, а не просто объединить все мутации в setImmediate? - PullRequest
0 голосов
/ 27 апреля 2018

Я начинаю изучать mobx, и я не понимаю, почему mobx изобрел сущность "действий". Будет ли проще просто поместить все изменения в следующий тик внутри setImmediate? Это автоматически заставит все изменения состояния синхронизации действовать так же, как это делает @action сейчас. Есть ли польза от запуска наблюдателей сразу после завершения действия, а не внутри следующего тика?

1 Ответ

0 голосов
/ 03 мая 2018

По разговору от https://github.com/mobxjs/mobx/issues/1523:

  1. setImmediate реализован только в IE и Nodejs. setTimeout (fn, 0) может вызвать задержку 4 мс
  2. https://hackernoon.com/the-fundamental-principles-behind-mobx-7a725f71f3e8: асинхронное обновление не будет иметь такой хорошей трассировки стека, чтобы найти, кто инициировал это обновление
  3. Реагирует на пакеты только вызовами setState от слушателей событий, как и моб-реакция. Это означает, что компонент React не будет повторно визуализироваться сразу после мутации, он будет синхронно обновляться только после обратного вызова слушателя событий.

Несколько примеров (все компоненты jsx должны быть внутри @observer):

// Ok to do this
<input value={appState.name} onChange={e => appState.name = e.target.value}/>


// Ok too, will rerender only once
<input value={appState.name} onChange={e => {
    appState.name = e.target.value; 
    appState.foo = appState.foo + 1;
}}/>


// Not very good, will rerender twice on each click.
// Nevertheless, I do not know why someone will do this
<button onClick={() => {
    setTimeout(() => {
        appState.foo = appState.foo + 1;
        appState.bar = appState.bar + 10;
    }, 0);
}}>Click me foo={appState.foo} bar={appState.bar}</button>


// But that way it will rerender once and show console output only once too
autorun(() => console.info(`App state foo={appState.foo} bar={appState.bar}`));
<button onClick={() => {
    setTimeout(() => {
        runInAction(() => {
            appState.bar = appState.bar + 10;
            appState.foo = appState.foo + 1;
        })
    }, 0);
}}>Click me foo={appState.foo} bar={appState.bar}</button>


// That code will show console output twice, but rerender only once
autorun(() => console.info(`App state foo={appState.foo} bar={appState.bar}`));
<button onClick={() => {
    setTimeout(() => {
        ReactDOM.unstable_batchedUpdates(() => {
            appState.bar = appState.bar + 10;
            appState.foo = appState.foo + 1;
        })
    }, 0);
}}>Click me foo={appState.foo} bar={appState.bar}</button>
...