mobx: Execute autorun not work when updating storage in the react context
Intended outcome:
Execute autorun when store is updated in react context
Actual outcome: not work
How to reproduce the issue: https://codesandbox.io/s/ceshigechongku-v2ypj?file=/src/App.js:1645-1647
The key code
--------global store and Context-----
const store = useLocalObservable(() => new MyState({}));
React.useEffect(() => {
store.init();
}, []);
return (
<singleSelectStoreContext.Provider value={store}>
<Wrap />
</singleSelectStoreContext.Provider>
);
------ A child component of <Wrap /> -------------
const rootStore = useSingleSelectStoreContext();
const state = useLocalObservable(() => ({
optionArr: [],
init(val) {
state.optionArr = val;
}
}));
React.useEffect(
() =>
autorun(() =>
// There's runInAction question here, and not wrapping it with an A would warn me,
// It's like here. https://github.com/mobxjs/mobx/issues/2718
runInAction(() => {
// The reason why I'm doing this is because I don't want to break the data in the global store
state.init(rootStore.initList);
})
),
[]
);
Versions mobx: 6.1.5 mobx-react: 7.1.0
About this issue
- Original URL
- State: closed
- Created 3 years ago
- Comments: 16 (6 by maintainers)
Won’t work correctly unless
initListis immutable (considering you want to re-run effect wheninitListchanges)You shouldn’t need to synchronize some “local state” with some “global state”. It’s antipattern. You should just move the local state to the global. https://github.com/mobxjs/mobx-react-lite/pull/302#issuecomment-678685286 https://github.com/mobxjs/mobx/issues/2710#issuecomment-759354434
It won’t, because the coupling already exists, otherwise you wouldn’t need to synchronize. You just want to move the coupling to some synchronization layer, but that itself won’t remove the coupling. You just make the application more complicated - it’s very likely that the “synchronized” component will never be used standalone outside of your application, therefore there is no practical reason to keep it “decoupled” and introduce some additional abstraction to keep it in sync. And even if you would need that, you have hooks - they can be easily moved around and plugged into any component, which allows you to do these refactors easily - eg if you have some complex component logic that depends on state, you don’t need to know where the state comes from - whether it’s global/local/props - you just pass the state as params to hook. Forget about mobx and observables and think how you would solve this with react alone - you want to copy state of some parent component into a state of a child component - it’s doable with
useLayoutEffect/getDerivedStateFromProps/componentDidUpdate, but you will be always advised to lift the state up instead.It’s not giving up local state - but you use local state for state that isn’t truly local.
Btw if you don’t need to keep the local state synchronized, but simply initialize it from global when template switches, then, well I would advise to initialize the template state in the action that changes the template, but you can also have a
ATemplate/BTemplate/etccomponent that is swapped with template and initializes it’s own state on mount (or eventually in layout effect that depends on some template id).EDIT: If you want to “hack” it, there is
_allowStateChanges, which you can use instead ofrunInAction, that will supress the warning.runInAction won't track anythingDon’t use
runInActioninautorun, it not work as your expected. It’s the final conclusion。React Hooks Deps
No, don’t do it. https://stackoverflow.com/questions/58579426/in-useeffect-whats-the-difference-between-providing-no-dependency-array-and-an
Fast Chinese Reply
solution for u
I know what you want to do.
Maybe you forgot the
useRefinReact hooksworld ?It works as expected in your codesandbox example.
runInAction won’t track anything, if you want to track store.name you have to access it outside the runInAction. I didn’t entirely get what the OP tried to achieve, but make sure to check https://mobx.js.org/react-integration.html#useeffect if you want to set up an effect that listens to observables
On Thu, Feb 18, 2021 at 1:51 PM ChenLei notifications@github.com wrote: