Improve the usability of Component State Reducers with state change types

InstructorKent C. Dodds

Share this video with your friends

Send Tweet

Users of our component can make custom modifications to the state whenever it changes, but in more complex components they may only want to change the state updates for certain types of changes. Let's add a type property to our changes object so people providing a state reducer have more insight into the source of the changes and can reduce the changes based on that information.

spencer
~ 6 years ago

Really cool stuff so far Kent. I'm trying to understand when you say that we are calling this.toggle with the event and you change it so getTogglerProps onClick property uses callAll(onClick, () => this.toggle()) instead. I've tried logging out what the callAll is outputting, or what args are sent to this.toggle, but I cant figure out why we changed it or how to see what you mean by "this.toggle is being called with the event". Would you mind elaborating on what exactly is going on? Thank you!

Kent C. Doddsinstructor
~ 6 years ago

Hi Spencer,

What's going on is the onClick will be called with the event just because that's the way React works. We pass onClick the function which is returned by callAll which will call the given functions with all the arguments it's called. So when that function's called with the event, it will then call toggle with the event. So we provide a function which calls toggle without any arguments which will cause the default argument to be picked up instead.

I hope that helps.

spencer
~ 6 years ago

Thank you so much for the explanation. Makes total sense now. Congrats on DownShift 2.0 as well 🏎

Viktor Soroka
~ 6 years ago

Hi Kent, Thanks for the material. As I understand you assigned a type for every action for consistency even though in that particular example it is enough just to provide the 'force' one. 'toggle' and 'reset' may be used later if needed, right? And another point I have is about a bit wrong behavior in the case when there are too many clicks and the force button was hit once, there is the ability to toggle state to the off state by clicking on the Toggler itself which should not be the case. Not a big deal though.

Bogdan Bivolaru
~ 6 years ago

Hi Kent, In internalSetState => setState you say we need to pluck the type to avoid necessary rerenders. Shouldn't we need to pluck the timesClicked too to avoid rerenders? Why not?

Indeed, I've seen the Usage component does not rerender, but I don't understand why! To verify this I've put an input field inside the Usage component - it does not lose its value when we toggle / force / reset.

A̶l̶s̶o̶,̶ ̶i̶n̶s̶i̶d̶e̶ ̶̶̶h̶a̶n̶d̶l̶e̶T̶o̶g̶g̶l̶e̶̶̶,̶ ̶i̶n̶s̶i̶d̶e̶ ̶̶̶s̶e̶t̶S̶t̶a̶t̶e̶̶̶ ̶I̶ ̶w̶o̶u̶l̶d̶ ̶e̶x̶p̶e̶c̶t̶ ̶t̶o̶ ̶b̶e̶ ̶a̶b̶l̶e̶ ̶t̶o̶ ̶o̶v̶e̶r̶w̶r̶i̶t̶e̶ ̶t̶h̶e̶ ̶o̶n̶ ̶k̶e̶y̶ ̶ ̶w̶i̶t̶h̶ ̶a̶ ̶s̶t̶r̶i̶n̶g̶,̶ ̶w̶h̶i̶c̶h̶ ̶I̶ ̶e̶x̶p̶e̶c̶t̶e̶d̶ ̶t̶o̶ ̶b̶r̶e̶a̶k̶ ̶t̶h̶e̶ ̶c̶o̶m̶p̶o̶n̶e̶n̶t̶.̶ ̶I̶t̶ ̶d̶o̶e̶s̶n̶'̶t̶ ̶-̶ ̶b̶u̶t̶ ̶w̶h̶y̶?̶

Oh, my sandbox: https://codesandbox.io/s/rwp5z49qo4

Kent C. Doddsinstructor
~ 6 years ago

Bogdan, timesClicked is state that's in the Usage component, not the Toggle. That's why not :)

Antonino Manno
~ 6 years ago

Hi Kent, I'm following this course, and I appreciate your work. In my opinion in this lecture when we insert the "Force toggle" function with type, we need to fix the toggleStateReducer

Now when you reach 4 timesClicked you will be able to "force toggle" once and then you can click on the switch and it will toggle even if we clicked more than 4 times :D So in this case we need to get "on" from the state and use that value in the return statement inside timesClicked > 4 condition

Paweł Waszczyński
~ 5 years ago

Quick questions: does the optimization with onlyChanges makes sense? I will return new object anyway (might be empty), but according to docs:

setState() will always lead to a re-render unless shouldComponentUpdate() returns false

Kent C. Doddsinstructor
~ 5 years ago

If you return null from your state updater (or simply pass null) then react will not trigger a rerender. If you return an empty object (or simply pass an empty object) then react will trigger a rerender.

See this codesandbox for an example: https://codesandbox.io/s/5wlvrkp5jn