2016-10-03 4 views
0

Я нахожусь на ранней стадии разработки игры React + Redux и следил за лучшими практиками Redux: чистое редукторное, презентационное/контейнерное разделение компонентов, используя только getState() в Reducer (в отличие от создателя действия) и т. д. Приложение, похоже, работает как ожидалось, но когда я пытаюсь изменить действие с помощью Time Travel, даже если свойство состояния map[][] и его вычисленный связанный компонент поддерживают изменение, как ожидалось, результат не отражается на пользовательском интерфейсе (особенно позиция игрока на карте не соответствует тому, что диктует состояние). Когда я проверяю изменения состояния, я вижу, что все необходимые изменения правильно происходят между разными состояниями. Вот мой редуктор:Redux DevTools Time Travel не обновляет пользовательский интерфейс правильно (только при повторном действии)

const gridReducer = (state, action) => { 

    if (typeof state === 'undefined'){ 
    let dungeon = new Dungeon(); 
    dungeon.generate(); 
    return { 
     boardWidth: Math.floor(((70/100) * window.innerWidth)/20), 
     boardHeight: Math.floor(((70/100) * window.innerHeight)/20), 
     map: dungeon.map, 
     position: dungeon.playerPosition 
    } 
    } 
    switch (action.type) { 
    case 'GRID_RESIZE': 
     return {...state, 
       boardWidth: action.newBoardWidth, 
       boardHeight: action.newBoardHeight 
     } 
    //This is where I have the issue, map correctly changes both when interacting with the game and when reversing using time travel however the UI fails to update (only in reverse)! 
    case 'MOVE': 
     let dungeonObj = new Dungeon(state.map.slice(), {...state.position}); 
     if (dungeonObj.movePlayer(action.direction)) { 
     return {...state, 
       position: dungeonObj.playerPosition, 
       map: dungeonObj.map 
       } 
     } else return state; 
    default: 
     return state; 
    } 
} 

Вот полный код, если вы хотите посмотреть! Приложение поддерживает только перемещение игрока в подземелье с помощью клавиш со стрелками, и вид должен всегда быть centeral на основе позиции игрока (игрок не двигаться назад при использовании путешествия во времени) http://s.codepen.io/sabahang/debug/GjrPNQ

PS: Dungeon.generate использует Math.Random, но я использую эту функцию только в initialState, и для отправленных действий я делаю только мелкую копию сгенерированной карты, отправив текущее состояние в конструктор Dungeon и используя его другие методы (например. movePlayer)

+0

Я пытаюсь сделать ваш код прямо сейчас, и, похоже, у него нет проблем с функцией Time Travel в моем браузере. (Кажется, вы оставили «отладчик» в строке 87, btw). –

+0

Я нажимаю кнопки со стрелками и запускает действие «MOVE», регистрируя его на боковой панели. Если я сброшу состояние на предыдущий с помощью инструмента отладки, он выглядит нормально. –

+0

@ DanielZendejas спасибо за напоминание отладчика, я удалил его. Не переустанавливайте состояние, а сделайте несколько шагов, а затем используйте ползунок временной трассы, чтобы переместить проигрыватель обратно в путь, по которому вы его перенесли (или переключите некоторые из промежуточных действий «MOVE».Это испортит положение игрока на карте (синяя точка не движется вообще или не реплицирует себя) –

ответ

1

Обнаружил преступника. Это вовсе не вина Redux, а то, как работает React! Если вы новичок в React, и вы еще не попали в эту ловушку, подождите ее! Это связано с тем, что большинство обычных способов копирования глубоко вложенного объекта, который необходим в Redux для реализации чистого редуктора, на самом деле делает мелкую копию объектов, а ссылки на память свойств все еще указывают на оригинальное государство. React обновляет пользовательский интерфейс на основе глубокого сравнения старого состояния и нового, и когда некоторые ссылки одинаковы, он не обновляет пользовательский интерфейс должным образом. Здесь у меня есть 2-мерный массив map[][], который является объектом, и хотя я использую оператор распространения ES6, чтобы избежать изменения исходного состояния, поскольку выполняется теневая копия, вносятся глубоко вложенные индексы исходного map[][]. Одним из решений было бы использовать `Array.map() 'для создания совершенно нового объекта, но я в конечном итоге использовал immutablejs, и он исправил мою проблему с помощью ползунка перемещения по времени.

Это настоятельно рекомендуется ссылка, если вы не хотите тратить недели чеканки подобных ошибок в сложных приложениях: http://redux.js.org/docs/recipes/reducers/ImmutableUpdatePatterns.html

и есть тонны неизменности помощников, чтобы помочь на основе ваших конкретных потребностей: https://github.com/markerikson/redux-ecosystem-links/blob/master/immutable-data.md#immutable-update-utilities

Это один также выглядит интересно Redux только: https://github.com/indexiatech/redux-immutablejs

Этот вопрос является потенциально дубликатом: React-redux store updates but React does not