2015-09-11 4 views
9

Я создаю приложение, в котором действия выполняются по мере прокрутки пользователя. Было бы неплохо, если бы я мог отменить эти действия, когда пользователь снова прокручивается, в основном поворачивая прокрутку в путь, чтобы просмотреть временную линию действий.Имеет ли Redux встроенный способ отмены действий?

Есть ли встроенный способ в Redux для этого? Или мне нужно написать для этого промежуточное ПО?

ответ

3

Я считаю, что идея не столько «отменить», сколько сохранить ссылку на все дерево состояний каждый раз, когда действие проходит через редукс.

У вас будет стек истории, состоящий из состояния приложения в разное время.

let history = [state1, state2, state3] 

// some action happens 

let history = [state1, state2, state3, state4] 

// some action happens 

let history = [state1, state2, state3, state4, state5] 

// undo an action 

let history = [state1, state2, state3, state4] 

state = state4 

Чтобы «отменить» действие, вы просто заменяете состояние приложения одним из сохраненных состояний.

Это может быть эффективно с структурами данных, которые поддерживают структурный обмен, но в разработке нам действительно не нужно слишком много учитывать ограничения ресурсов.

+0

Справа.Теперь я думаю, что мне придется написать редуктор, который реагирует на действия прокрутки, чтобы сохранить текущее состояние. Единственное, что я еще не знаю, как этот редуктор прочитал часть дерева состояний, которое я хочу сохраните, а затем скопируйте это в _different_ часть дерева состояний. Обратите внимание, что это не просто для развития; мой вариант использования - для реального взаимодействия с пользователем. – Vincent

+0

Если редуктору нужен доступ к двум различным частям дерева состояний, это, вероятно, означает, что вам нужен редуктор, который объединяет их обоих. – Qiming

+0

@ Vincent Или, что второе состояние на самом деле не является фундаментальным (то есть не является источником истины) и может быть отброшено – Qiming

1

Для этого не существует встроенного способа. , но вы можете получить вдохновение от того, как работают инструменты redux-dev-tools (https://github.com/gaearon/redux-devtools). В основном это функциональность «путешествия во времени», и она работает, отслеживая все действия и каждый раз пересматривая их. Таким образом, вы можете легко перемещать все свои изменения.

+0

Правильно, это сводится к написанию моего собственного промежуточного программного обеспечения? – Vincent

6

Есть ли встроенный способ в Redux для этого? Или мне нужно написать для этого промежуточное ПО?

В этом случае промежуточное программное обеспечение звучит как неправильная идея, потому что это касается чисто государственного управления. Вместо этого вы можете написать функцию, которая принимает редуктор и возвращает редуктор, «улучшая» его с отслеживанием истории действий на этом пути.

Я наметил этот подход в this answer, и он похож на то, как работает redux-undo, за исключением того, что вместо хранения состояния вы можете хранить действия. (Зависит от компромиссов, которые вы хотите сделать, и важно ли иметь возможность «отменить» действия в другом порядке, чем они были.)

+0

Это именно то, что я закончил делать, хотя я действительно сохранил состояние , Хотя не важно отменять действия в другом порядке, с точки зрения памяти было бы лучше хранить действия. Тем не менее, я понятия не имею, как я тогда буду увольнять их снова из моего редуктора - знаете ли вы, как это могло быть сделано? – Vincent

+0

@ Vincent Вам не нужно будет запускать их снова - просто пересчитайте 'present', запустив что-то вроде' state.actions.reduce (reducer) '. –

+1

Ха, имеет смысл, спасибо. Кроме того, я просто заметил, что ты мистер. Redux; Большое спасибо за эту отличную библиотеку! – Vincent

2

Я также хотел создать простую функциональность отмены, но уже отправил приложение с redux-storage, которое сериализует и загружает состояние для каждого пользователя. Поэтому, чтобы сохранить его обратно совместимым, я не мог использовать какое-либо решение, которое обертывает мои государственные ключи, например redux-undo с past: [] и present:.

Ищет альтернативу, Dan's tutorial вдохновил меня на переопределение combineReducers. Теперь у меня есть одна часть состояния: history, которая сохраняет до 10 копий остальной части штата и выталкивает их по действию UNDO. Вот код, это может работать для вашего случая тоже:

function shouldSaveUndo(action){ 
    const blacklist = ['@@INIT', 'REDUX_STORAGE_SAVE', 'REDUX_STORAGE_LOAD', 'UNDO']; 

    return !blacklist.includes(action.type); 
} 

function combineReducers(reducers){ 
    return (state = {}, action) => { 
    if (action.type == "UNDO" && state.history.length > 0){ 
     // Load previous state and pop the history 
     return { 
     ...Object.keys(reducers).reduce((stateKeys, key) => { 
      stateKeys[key] = state.history[0][key]; 
      return stateKeys; 
     }, {}), 
     history: state.history.slice(1) 
     } 
    } else { 
     // Save a new undo unless the action is blacklisted 
     const newHistory = shouldSaveUndo(action) ? 
     [{ 
      ...Object.keys(reducers).reduce((stateKeys, key) => { 
      stateKeys[key] = state[key]; 
      return stateKeys; 
      }, {}) 
     }] : undefined; 

     return { 
     // Calculate the next state 
     ...Object.keys(reducers).reduce((stateKeys, key) => { 
      stateKeys[key] = reducers[key](state[key], action); 
      return stateKeys; 
     }, {}), 
     history: [ 
      ...(newHistory || []), 
      ...(state.history || []) 
     ].slice(0, 10) 
     }; 
    } 
    }; 
} 


export default combineReducers({ 
    reducerOne, 
    reducerTwo, 
    reducerThree 
}); 

Для меня, это работает как шарм, он просто не выглядит очень красиво. Я был бы рад за любую обратную связь, если это хорошая/плохая идея и почему ;-)

Смежные вопросы