1) Mobx лучше использовать когда вы не хотите использовать монструозные конструкуции чтобы обновить какой-то объект который находится где-то глубоко внутри дерева состояния, например когда вам нужно обновить комментарий который находится внутри массива комментария объекта "задачи", которая находится внутри массива задач объекта "проекта" (схема примерно такая
store = {
projects: [
... ,
{id: 'project1', tasks: [
... ,
{id: 'task1', comments: [
{id: 'comment1', text: 'some text'}
]}
]}
]}
и где-то в компоненте комментария получив через пропсы объект {id: 'comment10', text: 'some text'} в обработчике ввода текста с mobx-ом вам достаточно будет обновить только одно свойство - comment.text = e.target.value, когда же с redux вам нужно создавать отдельный редюсер и там писать конструкцию которая сначала создаст новый объект коментария потом скопирует старые свойства и дальше запишет при этом свойство text с новым текстом, дальше создает объект задачи и также скопирует его свойства и создаст при этом новый объект массива комментариев и скопирует все комментарии которые были плюс наш новый объект комментария, и дальше все это нужно повторить с проектом и задачами и так с каждым родителем пока не доберемся до верхушки дерева состояния. Есть правда spread-оператор который облегчает этот процесс копирования свойств и элементов массива но конструкции все равно получаются монструозные и чем глубже объект тем они больше.
2) Mobx лучше использовать когда вы хотите чтобы какие-то объекты ссылались друг на друга. Например хотим создать todo-приложение но чтобы там можно было создавать подзадачи к задаче и подзадачи к подзадачам в общем чтобы получилось некое дерево подзадач. Со стороны реакта будет один компонент который рекурсивно будет вызвать себя для всех подзадач.
const Task = ({task})=> (
<div>{task.children.map(subtask=><Task task={subtask}>)}</div>
)
И теперь допустим вы решили ограничить количество подзадач к одной задачи. И хочется в обработчике написать примерно такое условие - if(this.props.task.parent.children.length > 10) return; то есть попросту говоря обратиться к объекту родительской задаче через свойство .parent. C mobx это возможно прямо как в этом примере а вот c redux это невозможно (потому что из-за того что объекты ссылаются друг на друга и необходимость возвращать новый объект состояния вызовет рекурсивное пересоздание всех объектов) и там для написания древовидных интерфейсов нужно делать нормализацию стора и передавать айдишник и писать еще кучу лишнего кода. И при этом не получится в обработчике обратится к объекту родителя так как this.props.task.parent будет айдишником и значит нам еще нужно обращаться к стору чтобы вытащить объект по его айдишнику (например через thunk - dispatch((_, getState)=>getState().tasks[this.props.task.parent]).children.length. А если нужно обратится к еще более родительской задачи - то нужно уже два раза вытаскивать объект из стора по его айдишнику. А в случае когда у нас большое приложение где у юзер может создавать папки, у папках проекты, у проектах задачи, у задачи комментарии то чтобы в компоненте комментария обратится к папке в котором находится комментарий c mobx достаточно просто написать comment.task.project.folder.name а вот с redux-ом будет примерно такая неудобная конструкция state.projects[state.projects[state.tasks[comment.taskId].projectId].folderId].name и в больших приложениях код бизнес-логики будет постоянно перемазан вот таким вот кодом вытаскивания объекта из стора по его айдишнику на каждый чих