简体   繁体   English

默认情况下返回突变的 state redux

[英]Default case returns mutated state redux

I am building a ETH portfolio tracker using ethplorer's API with React, redux-react and thunk middleware on the frontend.我正在使用 ethplorer 的 API 和前端的 React、redux-react 和 thunk 中间件构建一个 ETH 投资组合跟踪器。 The main component of the store is an array of objects (tokens).存储的主要组件是对象(令牌)数组。 You could see its reducer and actions below:您可以在下面看到它的减速器和操作:

import {createToken, initializeTokens, deleteToken, replaceTokens} from '../services/tokens'

const tokenReducer = (state = [], action) => {
  switch (action.type) {
    case 'ADD_TOKEN':
      return state.concat(action.data)
    case 'ERASE_TOKEN':
      return state.filter(token => token.address !== action.data)
    case 'INIT_TOKENS':
      return action.data
    default:
      return state
  }
}

//Defining Actions
export const addToken = address => {
  return async dispatch => {
    const newToken = await createToken(address)
    dispatch({
      type: 'ADD_TOKEN',
      data: newToken
    })
  }
}

export const updateTokens = () => {
  return async dispatch => {
    const updatedTokens = await initializeTokens()
    await replaceTokens(updatedTokens)
    dispatch({
      type: 'INIT_TOKENS',
      data: updatedTokens
    })
  }
}

export const eraseToken = address => {
  return async dispatch => {
    await deleteToken(address)
    dispatch({
      type: 'ERASE_TOKEN',
      data: address
    })
  }
}

export default tokenReducer

Imported functions are being used to fetch tokens from the API and then save them into a local database.导入的函数用于从 API 获取令牌,然后将它们保存到本地数据库中。 Another component of an action is a MarketCap filter (string) that I use to sort tokens according to their market cap (biggest to smallest, smallest to biggest or none).操作的另一个组件是 MarketCap 过滤器(字符串),我使用它来根据市值(从大到小、从小到大或无)对代币进行排序。 It has a super simple reducer and an action:它有一个超级简单的减速器和一个动作:

const mcReducer = (state='NONE', action) => {
  switch (action.type) {
    case 'SET_MC_FILTER':
      return action.filter
    default:
      return state
}
}

export const mcFilterChange = filter => {
  return {
    type: 'SET_MC_FILTER',
    filter
  }
}

export default mcReducer

The problem begins when I start sorting tokens for display in the React component.当我开始对标记进行排序以在 React 组件中显示时,问题就开始了。 While I do not intend to change the tokens state, and only want to change the array of displayed tokens, my tokens state neverthless changes to the sorted out one after I sort by the MC.虽然我不打算更改令牌state,而只想更改显示的令牌数组,但我的令牌state 在我按 MC 排序后不断更改为排序出来的一个。 So what happens is: programm dispatches SET_MC_FILTER => TokenList sorts tokens according to the filter => tokenReducer returns mutated state instead of the old one.所以会发生什么:programm 调度 SET_MC_FILTER => TokenList 根据过滤器对令牌进行排序 => tokenReducer 返回变异的 state 而不是旧的。 I don't understand why it happens, since I don't dispatch any actions that should affect the tokens state here and by default tokenReducer should just return the state that was stored in it.我不明白为什么会发生这种情况,因为我没有发送任何应该影响令牌state 的操作,默认情况下 tokenReducer 应该只返回存储在其中的 state。 Here is the last piece of code where the problem apparently happens:这是问题显然发生的最后一段代码:

const initTokens = useSelector(state => state.tokens)
const mcFilter = useSelector(state => state.mcFilter)

  const getDisplayTokens = inTokens => {
    switch (mcFilter) {
    case 'NONE':
      return inTokens
    case 'DESCENDING':
      return inTokens.sort(compareMCDescending)
    case 'ASCENDING':
      return inTokens.sort(compareMCAscending)
    default:
      return inTokens
  }}
  return(
    <div className='token-list'>
      {getDisplayTokens(initTokens).map(t =>
        <TokenTile token={t} key={t.id}/>
        )}
    </div>
  )

I have tried to track down the exact place where the tokens change with debugger and trace option of redux-devtools, but everywhere the tokenReducer instantly returns the changed state, and I have no idea why.我试图通过 redux-devtools 的调试器和跟踪选项来追踪令牌更改的确切位置,但是 tokenReducer 立即返回更改后的 state,我不知道为什么。 Any bits of help would be greatly appreciated任何帮助将不胜感激

Array.prototype.sort() mutates arrays in place. Array.prototype.sort()就地改变 arrays 。 You should never try to call .sort() directly on arrays that were read from the Redux state.您永远不应该尝试直接在从 Redux state 读取的 arrays 上调用.sort() You must make copies of the arrays and then sort them.您必须制作 arrays 的副本,然后对其进行排序。

Also, note that you should use our official Redux Toolkit package , which will both eliminate mutations in reducers, and throw errors if you ever try to mutate code outside of reducers.另外,请注意,您应该使用我们的官方 Redux 工具包 package ,它既可以消除减速器中的突变,也可以在您尝试在减速器之外修改代码时抛出错误。

Seehttps://redux.js.org/tutorials/fundamentals/part-8-modern-redux for a tutorial on how to use RTK correctly.有关如何正确使用 RTK 的教程,请参阅https://redux.js.org/tutorials/fundamentals/part-8-modern-redux

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM