State Management in Pure React, v2 Redo Reducer Solution
This course has been updated! We now recommend you take the React Performance course.
Transcript from the "Redo Reducer Solution" Lesson
>> All right, so this time, we're gonna start from the other angle. We'll actually write the reducer logic first. We'll say, action.type. Is REDO. And in this case, we'll say that the nearPresent is the first thing on the future, and then we'll call everything else in there the newFuture.
[00:00:23] So state.future. Cool. And then we'll say return, and we'll say the past, we'll take the current present and put it on there, As well as everything that was in the past previously. The present is the newPresent and not a dot, just a comma. And then the future is everything that was left in the future.
[00:01:03] That's the logic. And again, it seems how it was basically shifting stuff between arrays. It's like what are we putting the present, we're just moving stuff around. And so we've got that in place. Now, we want to probably have another action creator just like undo. We'll call this one, do you wanna take a lucky guess?
[00:01:25] Cuz I guess we're going forward from a past reality, that we have not changed. So if you change reality, that is a newFuture. And we do that, you'll notice that we're always replacing the future with an empty array. So if in any past time and you make a change, you lose access to all the futures again, it splits off to its own timeline.
[00:01:44] Again, there's a movie on this. It's a documentary about a purple guy who has not thought out how ecological systems work. Sweet. Yeah. So we'll pass in redo as well. One change that I've made, and if you're watching this, I've already re-based the branch. But for everyone else, is I changed the CSS a little bit.
[00:02:08] So if it's disabled, it is white and big. So we'll go into Application. And now for this other button, it's got a full width as well, we'll say disabled. We need to pull in the redo. And the isFuture as well. So we'll say disabled if there is no future.
[00:02:37] And we'll say onClick. Trigger our redo function. So right now, we're just in the initial state. There's nothing to undo, there's nothing to redo. For reasons, I'll say second. More reasons. So now I can undo, undo, redo, redo. So I can kind of like shift those different patterns around.
[00:03:14] Which again, gives us the ability to now do much more kind of complicated things with our state. I mean it's all just data structures at the end of the day. It's like kind of open this workshop with, like we ask java to take all these regular java script data structures.
[00:03:29] And figure out what to show into the UI, and we're kinda seeing the promise of that. And I would argue that having the reducers in there, and that kinda totally separate state management from even the use state or the component set state, makes it a lot easier to do more complicated things.
[00:03:45] For now, whatever you can logically think about in a structure, because it's a lot easier to implement using React. So you might be like, I want to do this everywhere. And we've already talked about the fact that writing the same code over and over again is silly, and you shouldn't do it.
[00:04:03] And so it will be great if we had some kind of, reusable, reducer pattern for this. And we've kind of seen this before. We did this a little bit with the thump reducer. We said, cool, useReducer is great, I have opinions on what should happen along the way.
[00:04:20] And what we did was, we used useReducer, and we had that advanced dispatch. And we enhance the dispatch to say always is a function, call the function and let it actually dispatch more things. So could we theoretically create something like const useundoReducer. That would take a normal reducer that just does the normal stuff.
[00:04:45] And given all that time travel ability. So now, you can take any reducer in your application instead of using useReducer we'll use undoReducer, and it will handle all of the kind of back and forth as well. So in order to do that, we know that it should have the same API as useReducer.
[00:05:05] So I will have reducer and initial state. And we know that it's going to eventually gonna wanna return something very similar, so we'll actually start out with return, useReducer. Again this is at noop, we're gonna have to fix this. Nope, I want useReducer, listen to me, I know what I'm doing.
[00:05:30] All right, well we'll do the reducer. State. All right, we're not actually gonna return these two values. What we're going to do is, we're gonna return a reducer that's gonna get all of these. We're gonna put it in our own special reducers, it's gonna catch the actions first.
[00:05:50] It's gonna do all the moving of the present, and the past, and the future. And then they can pass on a function for what the actual logic. Like, how do you add a grudge? How do you toggle forgiveness? So we'll separate the aspect of the time travel part, from the actual changing of the business logic.
[00:06:08] And you'll be able to use this useundoReducer, wherever you wanna have the ability to undo and redo in this case. So, they're gonna pass in initialState, cuz whoever uses this does not need to know anything about anything we just talked about. That is a secret for all of us, everyone in the live stream and anyone who watches this course.
[00:06:33] Right? It is our secret. We don't have to tell anyone about it. It will just give them useundoReducer. So, what do you need our own special version of state, we'll call it undoState which is going to be the past. The present will be whatever initial state they gave us.
[00:06:52] And the future will be an array. Very similar to what we had before. All right, now we'll make a special reducer. So we are underReducer which will be state and an action. And this is where the secret sauce happens. To find out what the new present is going to be, we'll call their reducer.
[00:07:20] Cuz whoever he is this reducers in charge of the business logic, this abstractions, only java is to shuffle between the past, present and future. So we'll say, const newPresent. Is whatever reducer they gave us, with the same state and the same action. Cuz they're gonna handle all of the forgiveness adding, whatever.
[00:07:43] So we'll get that newPresent out of their reducer. And we only care about these kind of special ones. So we'll say, if the action type is UNDO, and this is very similar from what we had before. We will say, in fact, I wonder if I can just copy and paste it.
[00:08:00] We'll see. I bet not. I'm writing this in application, so I am gonna need to move this function at one point. Let's do that now. Let's do it. Like honestly, this should be its own file, we're going to do in grudge context, just because that's where everything else is.
[00:08:18] So we kinda do it up top here. If the action is UNDO, and honestly we can take our UNDO or REDO logic, cuz all it is doing is that shuffling. So we could just take this wholesale. And we could rip that right out. And we can move it out into our undoReducer.
[00:08:40] Great. And so if UNDO or REDO. Otherwise, if it wasn't an UNDO action and it wasn't a REDO action, then we already have the new present cuz we called their producer. So we say that the past is state.present, state.past. The present is the newPresent we got from their's.
[00:09:10] And the future is unwritten. So now, what we're gonna do is we're just going to turn this back in, basically gonna undo everything that we did. Cuz now we just want a regular reducer, we wanna hide all of this from the person using it. So. If it's a grudge add.
[00:09:32] In fact, we could just cheat. That feels wrong. Let's actually put everything back the way it was. Somebody's job is to make sure I don't forget to remove a present at some point. I'll show you what I mean in a second. See that state.present? It's just, this reducer is exactly what we had before.
[00:09:55] undoReducer will handle all of the shuffling, we're just putting stuff back the way we found it. And so newPresent will simply be this. And we'll just. The other thing we need to do is, I wanna return my special undoReducer. And my special undoState. So their reducer just handles the present.
[00:10:32] It only does how to change the present, but before that, we intercept it, we get their newPresent, we populate the past, the present and the future for them. So barring some kind of mistake, which could happen cuz I did a lot of refactoring there. See, I forgot one.
[00:10:59] We should be able to go ahead, and we'll do this. Use. That should all theoretically work. UseReducer is not defined in application. That was that code that I had to get rid of. Save that file. grudges.map is not a function. Let's go in Grudges.js, there's probably something slightly off there.
[00:11:39] Let's just see what it is real quick. I'm passing it this broken default so when I give initial state, again is what I think it probably is. Yup. And so when we made that past, present, future like. Our reducer, we put it back to exactly the way things were before.
[00:11:56] It knows nothing about UNDO and REDO. The useundoReducer knows nothing about how to change the present. It only knows how to shuffle those states. So now now it has this like again, that same kind of theme, which is how do we take things that are coupled together and decouple them, so we can kinda use them interchangeably, which allows you to ship code a lot faster.
[00:12:16] Whoop. I don't actually need to follow state anymore. Yup, so just gotta clean some stuff up. This is now back to initialState. Great, so we'll hit Forgiven. So state.map is not a function. Let's go find out what state.map is. So we've got the past, present and the future.
[00:13:05] I think what I need to do is, the issue here is when I say the new president giving them all the state, I only want to give them access to the present. Cuz all their producer knows about is the present, ours like, we're trying to hide that from them.
[00:13:19] If we don't, things will Forgiven, undo, redo, right? So now, anyone can write a regular old reducer if they use undo reducer instead of use reducer, they get undo redo functionality for free, right? They don't have to think about it, we can now use it anywhere in our application, we will wanna have undo and redo.
[00:13:42] Which is super cool to think about these abstractions. Like, my boss has a wonderful sticker in his office, and it said. A week of coding saved us an hour of planning.
>> And so I think that that applies, thinking how do we break that apart? How do we take something that is two or three features all together and reusable parts.
[00:14:11] So we were able to ship features really fast, again by thinking about the state and how it works.