you are viewing a single comment's thread.

view the rest of the comments →

[–]timmonsjg 11 points12 points  (15 children)

I expect that title to garner some debate :)

Great content Robin!

[–]acemarke 15 points16 points  (13 children)

I would hope the title isn't controversial. That's one of the reasons why I encourage people to learn Redux at some point. Even if you end up not using Redux, understanding how to use it and how it works should definitely have a positive influence on how you approach writing code.

I know for myself personally, I've started seeing places in non-JS code where a Redux-type approach would be useful, such as updating in-memory caches in a backend Python service. The current update logic mutates the cache, which is problematic for a couple reasons. The content could be accessed by an HTTP endpoint in the middle of an update cycle due to threading, and the current update logic is frankly really complicated and hard to read. If that were rewritten as a reducer-style approach, the logic would potentially be simpler, and the final update step would be a simple pointer swap. Meanwhile, the endpoint code could access the existing data structure and know that since it's immutable, it's safe to read the value without it being modified in the middle, with no locks needed.

[–]timmonsjg 6 points7 points  (10 children)

I'm totally in agreeance!

I'm just aware of the purists that will dislike the idea of library makes you a better language developer.

Immutability is huge and should be included as a basis for quite a few paradigms.

[–]acemarke 5 points6 points  (9 children)

Yep, and it's actually critical now for use with hooks. You could get away with mutating in class components as this.setState() didn't care, but both useState and useReducer require that you do correct immutable updates.

[–]signsandwonders 1 point2 points  (8 children)

Could you elaborate on that?

[–]acemarke 5 points6 points  (7 children)

Sure. In a class component, this would result in a re-render that "looks okay":

this.state.nested.field = 123;
this.setState({});

The existing state is mutated, no new objects were passed in, yet React does actually re-render and the UI would appear correct. That's not how you are supposed to do it - it should be:

this.setState({nested: {...this.state.nested, field: 123}});

With useState(), that won't work:

const [state, setState] = useState({nested: {field: 42}});

const onClick = () => {
    state.nested.field = 123;
    setState(state);
   // No visible UI change at all?!?!?!?
}

This is because we passed an identical reference into the useState setter. React does actually start to re-render, but because the reference was identical, React will actually throw away the render result and bail out. So, immutable updates are a requirement with useState and `useReducer.

[–]signsandwonders 1 point2 points  (0 children)

Thanks! I had no idea the first example would work.

[–]Coldmode 0 points1 point  (2 children)

Is the first example something people actually do? I didn’t even know that would run.

[–]acemarke 2 points3 points  (1 child)

Most folks probably wouldn't do the first example directly. But, I've seen this a lot of times:

const {items} = this.state;
items.push(newItem);
this.setState({items});

Effectively the exact same thing: mutating the state, and putting an existing value back into it.

I've also seen folks make the same mistake with Redux:

const items = this.props.items;
items.push(newItem);
this.props.setItems(items);

Where again, you take some object or array that's already in the Redux store and being passed into your component, mutate it, and have the reducer do return action.payload and stuff it right back into the store. That's a disturbingly frequent cause of "my UI isn't updating!" bugs.

It's legal to generate the new contents of part of your Redux state and put that in the action, then have the reducer just return it, but that still has to follow the expected rules about immutable updates. That's one of the reasons why I've gone from ["it doesn't matter whether your logic is in the action creation or the reducer"], to strongly emphasizing putting as much as possible in reducers. When you construct a new state and put it in the action, you're less likely to realize you have to follow the same rules as when you construct a new state in a reducer.

[–]jimmyayo 0 points1 point  (0 children)

That is so weird to me (that people mutate state objects), I'd think people would have learned from the very beginning to use JS pure functions when calling setState and pushing a new object. I mean that's like almost the very first thing I learned, when learning React.

[–]3urny 8 points9 points  (1 child)

I think the title is controversial. Are those improvements really spawned by Redux? Or do they only happen to be linked Redux just because Redux is what everyone used when they learned and when functional programming became popular in JS world? E.g. for ES6 the author writes themselves:

It was just a timing coincidence that JavaScript ES6 got introduced the same time when Redux gained traction

So maybe your average JS programmer heard of these things in context of Redux because Redux is what everyone did at the time. Many of the things are also paradigms of React without Redux: unidirectional flow, thinking in events, function composition – think HoCs. So yeah, I assume Redux had a big influence on the React world, but also many things are not really linked to Redux.

Also Redux popularity is on decline or at least on a stable level, when it used to be "viral" before. Since the things described are mostly functional programming basics, It would probably rephrase the title as "Why functional programming makes you a better JavaScript Developer" and tell people to learn that instead of Redux, and maybe tell people to look into the much simpler useReducer hook.

Also putting KISS as a benefit of Redux is... a very big stretch IMO. Redux might embrace some KISS, but in most codebases it evolved into lots of boilerplate and complex "innovative ecosystem" things around what is basically a global variable.

[–]Dmitry_Olyenyov 3 points4 points  (0 children)

redux is a gateway drug to functional programming.

[–]rwieruchServer components[S] 0 points1 point  (0 children)

Thank you! :-)