The decoupling is quite easy to explain: in Redux you need to connect to the relevant parts of your state. The more your state tree differs from the component tree, the more often you have to do this. If you want to get the best performance possible, you should even adjust your state tree to exactly your components needs (see this twitter thread and test repo. This means that if you organize your UI differently, your state has to be adjusted.
In a lesser form this also applies to reducers. Where an action in mobx that updates just a todo only needs about the todo (e.g. toggleTodo(todo) => { todo.completed = !todo.completed }), the reducers also needs how the todo relates to the rest of the state tree in order to reproduce a new state, so you get something like:
toggleTodoActionImplementor(state, todoId) {
return {
...state,
todoId: {
...state[todoId],
completed: state[todoItem]
}
}
}
(some libraries make this easier of course)
So changing the state tree has a larger impact here (for example when changing from a todo map to an array or vice versa, the toggle action is affected by this!)
Controllers (basically a collection of action methods) in general don't relate to MobX. Like the above toggleTodo does nothing MobX specific. It would work with MobX observables and plain JS objects equally fine. The only MobX specific thing would be wrapping it in the future action decorator.
Controllers might use autorun to manage some side effects automatically, like sending data to the server, but you can also keep doing this 'by hand', explicitly.
Models do relate to MobX, they have a bunch of @observable and @computeds around. But again you can design them without MobX in mind and add the decorators as afterthough when you build the UI for example.
So because MobX is less opinionated and more flexible in how you structure your state, it is easier to decouple. Things like @observer work with all observables, regardless how you got them into your component. So if your component gets it's data from the context or even from a singleton in the closure, it will work anywhere in your component tree, without needing to change other parts of your application or restructuring the state tree.
Does that help?