I am building a ETH portfolio tracker using ethplorer's API with React, redux-react and thunk middleware on the frontend. 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. 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). 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. 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. 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. 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. 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. Any bits of help would be greatly appreciated