Does state changing is async?
tonoyandev opened this issue · 3 comments
I have React component, which connects to WebSocket server inside componentDidMount.
componentDidMount() {
const { connectWs } = this.props
connectWs(
true,
() => {},
() => {},
res => {
this.socketCallback(res)
},
)
}
socketCallback = payload => {
const { handleClaimSuccess } = this.props
const { horse_id, race_id } = payload
const data = {
'horseId': horse_id,
'raceId': race_id
}
handleClaimSuccess(data)
}
render() {
const { claimed } = this.props
return (
<div>
{claimed.map((data, index) => (
<div className="primary-text">
{ data.isPending ? 'PENDING' : 'COLLECTED' }
</div>
)}
<div>
)
}
The server sends 3 messages via sockets, which component handles and sends to reducer for updating the state. The time difference between that 3 messages is 30-60 microsecond.
'handleClaimSuccess': (state, { payload }) => {
if (payload) {
const { horseId, raceId } = payload
const updatedWinnings = state.userWinnings
const indexOfWinningInClaimed = findIndex(updatedWinnings.claimed, {
'horseId': horseId,
'race': {
'raceId': raceId
},
})
updatedWinnings.claimed[indexOfWinningInClaimed].isPending = false
return {
...state,
'userWinnings': updatedWinnings
}
}
return state
}
All messages change the state accordingly, but component renders results only once (after 1st message) and ignore next 2 messages.
As I understand its related to small interval of messages, cause it works fine with single messages.
How it can handle all 3 messages and render the state after each message?
I don't have a whole answer for you, only one part.
Your reducer is mutating some of the state, instead of recreating it all. You have this line:
updatedWinnings.claimed[indexOfWinningInClaimed].isPending = false
... which changes the value of isPending
on one item from a collection. However, you are not then making a new item with the new property value; you are returning the same item with the value mutated. Also, you are not returning a new .claimed
array; only the same array with one property of one member changed. Because of this, the store
->selectors
->connect()
->props
->shouldComponentUpdate()
sections of the component lifecycle will (probably) not notice that updatedWinnings.claimed[indexOfWinningInClaimed]
has changed.
You could try modifying this reducer to make a new updatedWinnings.claimed
array, with a new [indexOfWinningInClaimed]
item, with the new .isPending
value.
My preference would be to extract more and more specialised reducers. The one you have now operates on the collection. Make a new one which operates on an item in the collection (handling any actions it may need). You might need to go deeper still if the other data in updatedWinnings.claimed[indexOfWinningInClaimed]
is rich and nested.
(This is likely not a problem with redux-actions
. You might get better answers if you ask again on StackOverflow with a [redux]
tag. However, redux-actions
can help you: its handleActions()
function makes it much easier to create layers of reducers with pass smaller and smaller pieces of state, and the action, to one another.)
@simondell thanks, yes that was not related to redux-actions
. Closed.