【问题标题】:Default case returns mutated state redux默认情况下返回变异状态
【发布时间】:2020-12-18 18:07:53
【问题描述】:

我正在使用 ethplorer 的 API 和前端的 React、redux-react 和 thunk 中间件构建一个 ETH 投资组合跟踪器。存储的主要组件是一个对象数组(令牌)。你可以在下面看到它的减速器和动作:

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

导入的函数用于从 API 获取令牌,然后将它们保存到本地数据库中。操作的另一个组件是 MarketCap 过滤器(字符串),我使用它来根据市值(从大到小、从小到大或无)对代币进行排序。它有一个超级简单的减速器和一个动作:

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

当我开始对标记进行排序以在 React 组件中显示时,问题就开始了。虽然我不打算更改 tokens 状态,而只想更改显示的令牌数组,但我的 tokens 状态在我排序后仍然会更改为已排序的状态主持人。所以发生的事情是:programm 调度 SET_MC_FILTER => TokenList 根据过滤器对令牌进行排序 => tokenReducer 返回变异状态而不是旧状态。我不明白为什么会发生这种情况,因为我没有在这里调度任何应该影响 tokens 状态的操作,并且默认情况下 tokenReducer 应该只返回存储在其中的状态。这是显然出现问题的最后一段代码:

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>
  )

我尝试使用 redux-devtools 的 debugger 和 trace 选项追踪 tokens 更改的确切位置,但是 tokenReducer 立即返回更改状态的任何地方,我不知道为什么。任何帮助将不胜感激

【问题讨论】:

    标签: javascript redux react-redux


    【解决方案1】:

    Array.prototype.sort() 就地改变数组。你永远不应该尝试直接在从 Redux 状态读取的数组上调用 .sort()。您必须制作数组的副本,然后对它们进行排序。

    另外,请注意您应该使用our official Redux Toolkit package,它既可以消除reducer 中的突变,也可以在您尝试修改reducer 外部 的代码时抛出错误。

    请参阅https://redux.js.org/tutorials/fundamentals/part-8-modern-redux 获取有关如何正确使用 RTK 的教程。

    【讨论】:

    • 谢谢!使用[...initTokens] 复制数组并对其执行排序确实有帮助。为了以后避免这样的头痛,我会实现 RTK 并弄清楚如何使用它
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-16
    • 1970-01-01
    • 2011-06-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多