2015-10-15 2 views
29

Потерпите меня здесь, так как этот вопрос относится к моему первому тестовому приложению, используя либо React, Redux, либо react-redux. Документы получили меня далеко, и у меня есть макет банковского приложения, которое работает в основном. Мое состояние объекта выглядит примерно так:React-redux хранит обновления, но не реагирует

{ 
activePageId: "checking", 
accounts: [ 
    checking: { 
    balance: 123, 
    transactions: [ 
     {date, amount, description, balance} 
    ] 
    } 
] 
} 

У меня есть только два действия:

1. CHANGE_HASH (как в URL-адрес хэш). Это действие всегда работает так, как ожидалось, и все редукторы действительно обновляют state.activePageId (да, я клонирую объект состояния и не изменяю его). После действия я вижу, что состояние изменилось в хранилище Redux, и я вижу, что React обновился.

function changeHash(id) { 
     return { 
      type: "CHANGE_HASH", 
      id: id 
     } 
} 

2. ADD_TRANSACTION (форма представления). Это действие никогда не обновляет React, но всегда обновляет хранилище Redux. Редуктором для этого действия является обновление state.accounts [0] .balance и добавление объекта транзакции в состояние state.accounts [0] .transactions. Я не получаю никаких ошибок, React просто не обновляется. ОДНАКО, если я отправлю действие CHANGE_HASH, React догонит и правильно отобразит все состояния ADD_TRANSACTION.

функция addTransaction (транзакция, баланс, счета) { возврата { типа: "ADD_TRANSACTION", полезная нагрузка: { транзакций: транзакции, баланс: баланс, счетов: счет } } }

Мой редуктор ...

function bankApp(state, action) { 
    switch(action.type) { 
     case "CHANGE_HASH": 
      return Object.assign({}, state, { 
       activePageId: action.id 
      }); 
     case "ADD_TRANSACTION": 
     // get a ref to the account 
      for (var i = 0; i < state.accounts.length; i++) { 
       if (state.accounts[i].name == action.payload.account) { 
        var accountIndex = i; 
        break; 
       } 
      } 

     // is something wrong? 
      if (accountIndex == undefined) { 
       console.error("could not determine account for transaction"); 
       return state; 
      } 

     // clone the state 
      var newState = Object.assign({}, state); 

     // add the new transaction 
      newState.accounts[accountIndex].transactions.unshift(action.payload.transaction); 

     // update account balance 
      newState.accounts[accountIndex].balance = action.payload.balance; 

      return newState; 
     default: 
      return state; 
    } 

Мои mapStateToProps

function select(state) { 
    return state; 
} 

Что мне здесь не хватает? У меня создается впечатление, что React должен обновляться по мере обновления магазина Redux.

Github репозиторий https://github.com/curiousercreative/bankDemo Развертывание: http://curiousercreative.com/demos/bankDemo/

P.S. Я солгал, что у меня нет ошибок. У меня есть несколько предупреждений »« Предупреждение: каждый дочерний элемент в массиве или итераторе должен иметь уникальную «ключевую» опору ... «Я уже даю им ключ, установленный в его индекс. Я сомневаюсь, что у него есть что-нибудь делать с моим вопросом, хотя

+1

Хм, я думаю, что две вещи, которые помогут сузить ошибку: 1) использование [перевождь-регистратор] (https://github.com/fcomb/redux-logger), чтобы увидеть, что изменилось, когда действие происходит 2) разместите свой код редуктора, действия и mapStateToProps. – Cheng

+0

К сожалению, мне не удалось заставить работать редукционный логгер, но я сам что-то сделал, и все работает там, как ожидалось. Теперь я обновлю вопрос с помощью редуктора, действий и mapStateToProps. – curiouser

+0

Как React определяет, изменилось ли состояние? Возможно, потому что изменение довольно глубокое в объекте состояния, и изменение настолько мало, что это не повторное рендеринг? Как реагирует-редукт решает, когда обновлять реквизиты React? Я просто выписал значение состояния в mapStateToProps, и он обновлен там, только не в React. – curiouser

ответ

44

проблема в этом фрагменте кода:..

 // clone the state 
      var newState = Object.assign({}, state); 

     // add the new transaction 
      newState.accounts[accountIndex].transactions.unshift(action.payload.transaction); 

     // update account balance 
      newState.accounts[accountIndex].balance = action.payload.balance; 

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

Эта проблема и ее решение подробно описаны в документах Redux «Устранение неполадок», поэтому я предлагаю вам их прочитать.

https://redux.js.org/troubleshooting

Я также предлагаю вам взглянуть на пример Покупки карты в Flux Сравнение для Redux, поскольку он показывает, как обновить вложенные объекты, не мутирует их подобным образом, что вы просите.

https://github.com/voronianski/flux-comparison/tree/master/redux

+7

Спасибо! Я прочитал эти документы и попытался сохранить объект состояния, однако мое недопонимание в методе Object.assign. Хотя это создавало новый объект из исходного объекта, это был только мелкий объект клонирования, объекты, вложенные в объект состояния, не были клонированы, но все же ссылались на объекты вложенных объектов исходного состояния. Я не сталкивался с этим свойством с другим действием, потому что никаких вложенных объектов не изменялось. Хорошая рецензия на клонирование объектов (№ 5 - это то, что меня достало): http://blog.soulserv.net/understanding-object-cloning-in-javascript-part-i/ – curiouser

+7

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

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