I have this inside my reducer
if (action.type == 'NEW_TWEET') {
const id = uuid.v1();
const tweets = {
[id]: {
id,
text: action.text,
authorId: state.myUser.id
},
...state.tweets
}
return {...state, tweets}
}
Random id from uuid.v1() makes it non-pure function. I suppose that this is not a problem because I will never write any logic that depend on predictable id. And there is no sanity in writing unit test which check that new id is correct. Am I right or not?
Don't do it. The whole point of a "reducer" is that it is pure and deterministic. Even if it doesn't break anything right now, it's a very bad habit to follow. If you need non-determinism, like creating new Dates or UUIDs, do it in an action creator.
Well. I have habit to think before do something and will not follow "habit of writing non pure reducers" if there are adequate alternatives. Generating and passing id from actions seems more inadequate for me.
I'll counterbalance @markerikson's answer. In my opinion it's fine to generate this kind of data within the reducer. You don't have make your reducer 100% pure. What matters is how easy you will be able to maintain this code. If you don't need strict predictability, then it's fine!
Let's consider another use case.
function log(payload) {
return {type: "LOG", payload}
}
function logReducer(state = [], action) {
switch (action.type) {
case "LOG":
return state.concat({ts: Date.now(), data: String(action.payload)})
default:
return state
}
}
function actionCounterReducer(state = 0, action) {
return state + 1
}
The logReducer is no longer pure because it depends on Date.now(). actionCounterReducer also consumes LOG and is pure. It has no knowledge about when the action was dispatched and adding this information to the action is non-sense. Sometimes you simply don't have better options than making your functions impure.
I'm closing the issue but feel free to continue the discussion.
Impure reducers make writing tests harder (you don鈥檛 know exactly what you鈥檙e going to get) as well as screw up replaying actions recorded from user sessions (IDs don鈥檛 match anymore). Generating IDs in action creators solves these problems.
Similarly, Redux DevTools replay your reducers when you change their code so you鈥檒l get different IDs every time you save a file which is likely to screw up the logic, as your later actions likely rely on these IDs. Same problem with enhancers like https://github.com/omnidan/redux-undo. If you don鈥檛 use any of these tools though it鈥檚 fine鈥攋ust be aware that you might bump into limitations later.
The answer for a number of these things tends to be "well, it is _technically_ possible to do that, but you break stuff like time-traveling, which is a big part of why you'd even want to use Redux in the first place".
I pick Redux for another reason, but you all have good point and I definitely have to try all those dev tools
Most helpful comment
Impure reducers make writing tests harder (you don鈥檛 know exactly what you鈥檙e going to get) as well as screw up replaying actions recorded from user sessions (IDs don鈥檛 match anymore). Generating IDs in action creators solves these problems.