1 00:00:02,180 --> 00:00:05,330 In the last lecture, we outsourced our action types, 2 00:00:05,450 --> 00:00:14,720 there is something else we do a lot as our application grows and that is use multiple reducers. 3 00:00:14,810 --> 00:00:22,310 Now I did say that we only have one reducer with redux and this is the case, all actions in the end get 4 00:00:22,310 --> 00:00:30,560 funneled through one reducer but redux, the package gives us a utility method we can use to combine 5 00:00:30,560 --> 00:00:38,360 multiple reducers into one, so that we still follow the pattern of having only one reducer behind 6 00:00:38,360 --> 00:00:39,520 the scenes 7 00:00:39,530 --> 00:00:46,880 but for us as a developer, that we can split up our code logically so that we dont get one huge reducer, 8 00:00:47,090 --> 00:00:53,270 imagine how this reducer would grow as we add more and more action types we want to handle but that 9 00:00:53,270 --> 00:00:58,290 we can split it up by feature. In our tiny demo application, 10 00:00:58,340 --> 00:01:05,360 it might make sense to have a reducer which handles the counter and one which handles the results, even 11 00:01:05,360 --> 00:01:07,420 though they're somehow related, 12 00:01:07,580 --> 00:01:14,750 they technically are different or they manage different parts of the app so splitting it up might make 13 00:01:14,750 --> 00:01:15,280 sense 14 00:01:15,290 --> 00:01:18,020 and this is exactly what we're going to do. 15 00:01:18,050 --> 00:01:25,520 So let's split our reducer here into two reducers, one for the counter related parts of the switch case 16 00:01:25,520 --> 00:01:28,800 statements and one for the results related one. 17 00:01:28,820 --> 00:01:36,830 So for that I'll simply add here in my store folder, I'll add a new reducers folder and then I'll add a 18 00:01:36,830 --> 00:01:45,080 file which I'll name counter.js and one which I'll name result.js 19 00:01:45,150 --> 00:01:51,660 Now I'll copy all the code from my reducer.js file and put it into the counter.js file, 20 00:01:51,690 --> 00:01:58,320 I need to adjust the path to my actions file now by simply going up one level and then here, we are 21 00:01:58,320 --> 00:02:01,200 in the folder where the action.js file lives. 22 00:02:01,760 --> 00:02:02,610 The initial state 23 00:02:02,610 --> 00:02:07,590 now here in this file no longer needs to know about the results array, it's just about the counter here, in 24 00:02:07,670 --> 00:02:09,250 the counter.js file, 25 00:02:09,400 --> 00:02:15,360 the reducer function still looks as before, state which is assigned the initial state and we receive 26 00:02:15,360 --> 00:02:16,550 an action, 27 00:02:16,560 --> 00:02:22,380 I just get rid of the result related cases here to make this a bit slimmer, 28 00:02:22,410 --> 00:02:25,320 this already is my finished reducer. 29 00:02:25,320 --> 00:02:29,280 We can name this here counterReducer, this function, 30 00:02:29,280 --> 00:02:33,000 we can also leave it named reducer, whatever you like. 31 00:02:33,000 --> 00:02:38,610 Now I'm again going to copy the code from the reducer.js file and put it into my results.js 32 00:02:38,620 --> 00:02:44,790 file, again adjust the path to the actions file and now I'm going to get rid of the counter property in 33 00:02:44,790 --> 00:02:52,080 my initial state. The reducer then still stays as it is, but I remove all counter related cases so that 34 00:02:52,140 --> 00:02:54,910 only the store related ones are there. 35 00:02:54,930 --> 00:03:03,690 Notice that I still access state.Counter in here because in the end, the two reducers are going to 36 00:03:03,690 --> 00:03:07,230 get merged together into one global state 37 00:03:07,470 --> 00:03:12,330 so there still is going to be a counter state in there, 38 00:03:12,330 --> 00:03:15,980 we still might need to update this later but we'll see. 39 00:03:16,410 --> 00:03:19,010 Then I'll still export my reducer here 40 00:03:19,260 --> 00:03:24,500 and this allows me to get rid of my reducer.js file in the store folder. 41 00:03:24,520 --> 00:03:26,940 Now of course, in index.js, 42 00:03:27,010 --> 00:03:28,900 I no longer have a valid import 43 00:03:28,900 --> 00:03:31,120 here, this reducer doesn't exist, 44 00:03:31,120 --> 00:03:33,140 instead I now have two reducers, 45 00:03:33,220 --> 00:03:35,080 so let's import them. 46 00:03:35,080 --> 00:03:43,810 Let's go into the store folder, into the reducers folder and import counter.js and I'll name this 47 00:03:43,900 --> 00:03:45,080 counterReducer here, 48 00:03:45,250 --> 00:03:51,570 I'll duplicate the import to then also import the result reducer from the store 49 00:03:51,580 --> 00:03:55,990 reducers results.js file. 50 00:03:56,080 --> 00:04:01,640 Now to combine them, I need to import a helper function from the redux package, 51 00:04:01,720 --> 00:04:06,040 it's called combineReducers, as the name suggests, 52 00:04:06,070 --> 00:04:14,290 this is a function which takes a javascript object mapping our reducers to different slices of our 53 00:04:14,290 --> 00:04:21,510 state as input and merges everything into one state and one reducer for us. 54 00:04:21,510 --> 00:04:26,680 So here before creating the store, I'll create a new constant which I'll name rootReducer, the name is up to 55 00:04:26,680 --> 00:04:30,000 you though and I'll call combinedReducers. 56 00:04:30,040 --> 00:04:38,500 Now as I just said, this function takes a javascript object as an input and there, we now simply can create 57 00:04:38,710 --> 00:04:45,850 sections of our app so to say, any name you want like the counter or just ctr, whatever you want, 58 00:04:45,850 --> 00:04:53,650 I'll name it ctr here here and map the counter reducer to it and then I'll add my res area with 59 00:04:53,650 --> 00:04:56,710 the resultReducer. 60 00:04:56,730 --> 00:05:03,750 So now we're telling redux in the end, hey I got two different feature areas in my application, 61 00:05:03,780 --> 00:05:05,400 ctr and res, 62 00:05:05,630 --> 00:05:12,860 please use these reducers for each of them and merge everything together into one store, into one state, 63 00:05:12,960 --> 00:05:14,980 into one reducer. 64 00:05:15,020 --> 00:05:21,890 If we now pass the rootReducer here to create store and save all the files, we shouldn't get an error 65 00:05:21,890 --> 00:05:22,640 down there 66 00:05:22,670 --> 00:05:29,560 when npm start runs. In the application though, if we reload it, we will get an error 67 00:05:29,750 --> 00:05:32,930 that map can't be executed on undefined 68 00:05:33,380 --> 00:05:40,430 and basically here, the problem is that stored results where we map through all the stored results, that 69 00:05:40,490 --> 00:05:49,370 this won't work because this props stored results now refers to undefined and not to an array of results 70 00:05:49,370 --> 00:05:50,320 anymore. 71 00:05:50,480 --> 00:05:53,510 This happens due to us combining reducers, 72 00:05:53,510 --> 00:06:02,240 now we will have one state in the end but to avoid naming conflicts, redux adds one level of nesting 73 00:06:02,600 --> 00:06:05,760 where it has one state object 74 00:06:05,900 --> 00:06:13,400 but basically with these keys here, in combined reducers as properties which give us access to these sub 75 00:06:13,400 --> 00:06:21,740 states for these feature areas, you could say. So in the counter.js file, if we want to access the counter 76 00:06:22,430 --> 00:06:30,200 we have to access the global state.ctr.counter, .ctr 77 00:06:30,410 --> 00:06:38,170 since this is the name we gave this slice of our global state and for the result, it would be .res. 78 00:06:38,270 --> 00:06:43,130 So here, it's state.res, like this. 79 00:06:43,160 --> 00:06:47,030 Now if we save this, the application is not broken anymore 80 00:06:47,360 --> 00:06:52,180 and if I now click a button it works, the same for storing results 81 00:06:52,220 --> 00:06:59,520 though here we see it adds results but somehow it's not really adding them, 82 00:06:59,660 --> 00:07:02,250 not really displaying them here. 83 00:07:02,270 --> 00:07:09,740 The reason for this is that the stored result actually is undefined because in the resultReducer, we do 84 00:07:09,740 --> 00:07:20,040 store a snapshot here for state.Counter and this doesn't work because this now, state.Counter, is not known 85 00:07:20,700 --> 00:07:29,160 because this local initial state in this reducer doesn't have a counter property. 86 00:07:29,160 --> 00:07:35,250 Now you could think that you simply add state.ctr.counter, if you do this and save everything, click 87 00:07:35,250 --> 00:07:42,590 add 10 and click store result, you get an error though that you can't read property counter of undefined. 88 00:07:42,590 --> 00:07:49,020 The reason for this is that inside this reducer function, it basically has no access to the global state 89 00:07:49,410 --> 00:07:52,680 only to that state of that reducer function. 90 00:07:52,680 --> 00:07:57,820 That's different than the counter component where we connect our react component to the global state, 91 00:07:57,960 --> 00:08:02,130 there we can access the different pieces of the state through our slices 92 00:08:02,130 --> 00:08:03,230 we set up in index.js 93 00:08:03,300 --> 00:08:03,890 . 94 00:08:04,020 --> 00:08:08,060 This does not work inside of the reducers. 95 00:08:08,160 --> 00:08:17,750 So if we are in a reducer where we need to get a value from the global state, we should simply get it 96 00:08:18,260 --> 00:08:20,500 as an action payload 97 00:08:20,630 --> 00:08:23,590 and this is generally how your reducers work anyways 98 00:08:23,600 --> 00:08:32,740 most of the time, it's old state plus action plus optionally action data and you return a new state. 99 00:08:33,080 --> 00:08:39,950 So here I expect to get that same result property on my incoming action and to receive that, I need to 100 00:08:39,950 --> 00:08:45,090 adjust my counter.js file. There where I execute on store 101 00:08:45,110 --> 00:08:50,510 result, here I in the end just need to get my result 102 00:08:50,780 --> 00:09:00,480 so I expect to get my result here as an argument and then I can simply pass this along with the type, use 103 00:09:00,480 --> 00:09:01,170 the key 104 00:09:01,250 --> 00:09:02,730 you chose to use here, 105 00:09:03,590 --> 00:09:05,040 action result. 106 00:09:05,100 --> 00:09:07,660 So we should have a result property here 107 00:09:07,660 --> 00:09:16,870 too in the object we dispatch, we bind or we set the value to the result argument we expect to get here 108 00:09:17,120 --> 00:09:24,110 and now to get it just like before with deleting, we execute this here on the button as an anonymous 109 00:09:24,110 --> 00:09:29,750 function so that we can pass some data here on store result, should now be 110 00:09:29,760 --> 00:09:33,040 this.props.ctr gives us access to the counter 111 00:09:33,230 --> 00:09:36,950 and that's actually the value we want to store. 112 00:09:37,040 --> 00:09:44,960 Now if we go back and I click add 10, I can store 10 again, by the way if you hit store result really 113 00:09:44,960 --> 00:09:52,210 fast after each other, you will get this error simply because the ID we assign is the current date 114 00:09:52,370 --> 00:09:58,160 and if you hit this very rapidly, there will simply be the same date assigned twice which leads to this 115 00:09:58,160 --> 00:09:58,780 error, 116 00:09:58,820 --> 00:10:03,590 it's of course just a temporary ID solution here, not one you would use in production, 117 00:10:03,590 --> 00:10:05,750 so for me here it doesn't matter. 118 00:10:05,750 --> 00:10:12,200 The core takeaway is how you can split your reducers into different slices and how you then still make 119 00:10:12,200 --> 00:10:16,670 sure you get the data you need in each of these slices.