in ,

I created the exact same app with React and Redux. Here are the differences., Hacker News

I created the exact same app with React and Redux. Here are the differences., Hacker News


React vs Redux. Finally, a side-by-side code comparison between React and Redux!

Sunil Sandhu

It can be a great feeling once you’ve managed to learn how to use React and can confidently built a few apps. You’re able to manage state and everything seems to be working fine. However, it’s quite possible that a time may arrive where you have to learn Redux.

This may be because the app that you’ve been working on has gotten larger and larger and you’ve found yourself passing state all over the place and need a better way of managing your data. Or it may just be because you’ve noticed that a ton of job adverts require knowledge of Redux as well as React. Either way, knowing how to use Redux is a great piece of knowledge to have, and you should therefore, owe it to yourself to learn it.

However, one thing that can make it difficult to pick up is the amount of additional code you have to wrap your head around in order to understand how it works. I personally also feel that the documentation out there, including the official Redux docs, show so many different approaches to using Redux, that Redux no longer feels approachable.

In a way this is kind of a good thing, because it encourages you to use Redux in the way that you see fit, rather than saying“this is exactly how you should use it, and if you don’t then you are a bad developer”.However, this nicety doesn’t arrive until you know what you’re doing with Redux, which until then, just makes it really hard to pick up.

So how are we going to learn Redux?

By building an app with React, and then building the exact same app with Redux!

Oh and by the way, when I say “building an app with Redux”, we are still using React – we’re simply managing the flow of data with Redux. But from here on, apart from some tangents along the way, when I refer to the app being built with Redux, I really mean being built with React AND Redux.

React vs Redux. Not a battle as such, but rather a variation of approach to your app.

Because these are both React apps that have been created withcreate-react-app,their file structure is mostly identical, with the exception of aReduxfolder inside of the Redux app. Let’s take a look at the file structure now:

React on the left . Redux on the right.

Now given that these two apps achieve the exact same thing, you might be wondering why Redux requires so many additional files, and what purpose they serve.

The first thing you will notice is the large amount of initial boilerplate code needed in order to get Redux set up for your app. This is, in large part and the mental model it applies – Redux also has its roots in functional programming but let’s save this rabbit hole for another occasion. Anyway, this additional code can really pay off when building larger applications that have lots of data flowing in and out of various components, APIs etc. So it may seem like overkill for this simple To Do app at first, but just stick with us as we’re not trying to encourage you to use Redux for simple apps, but rather we’re using this on a simple app in order to make Redux a little easier to pick up and understand.

Redux handles the flow of data through three key principles:

1. Stores

Also known as a single source of truth, a store is basically just an object that you initialize with some state, then whenever we want to update it, we overwrite the store with a new version of it. You may already be using these same principles in your React applications anyway, as it is generally considered a best practice to recreate state rather than mutating it. To further clarify the difference here, if we had an array and we wanted to push a new item into it, we wouldn’t update our store by pushing a new item into the array, but rather we would overwrite the store with an updated version of it.

2. Reducers

So our store gets updated through something known as a reducer. These basically are the mechanisms by which we send our new versions of state. That may not make much sense just yet, so let’s elaborate a little. Let’s say we have our store object and it has an array that looks like this:list: [{‘id: 1, text: ‘clean the house’}]. If we had a function that adds new items into our array, our reducer will explain to our store how the new version of our store will look. So in the case of ourlistarray, we would likely grab the contents of our list, spread it into a new (list) array through the...syntax, along with the new item we want to add. Therefore, our reducer for adding new items may look something like this:list: [...list, newItem]. This is also what we mean here when we discussed how we create new copies of our state for the store, rather than pushing new items into existing parts of it.

3. Actions

Now in order for our reducers to know what new data to put into our state, they have access to a payload. This payload is sent to our reducer through something known as an action. An action is typically accessible within the components in our app – via props – just like any function we create. Because these actions are in our components, we can pass them parameters – these become the payloads.

So with that in mind,

We can think of Redux in the following way: Our app has access toactions.These actions carry data (or a payload as it generally tends to be called) from our app.Actionshave a type that it shares with a (Reducer) . Whenever theactiontypegets triggered, it picks up the payload and tells ourstorehow it should now look – by which we generally mean how should our data object look now that it has been updated.

There are other parts to this Redux mental model, such as action creators and action types, among others – but these additional elements are not required for our To Do app.

The Redux setup here may be a good starting point for you and you might decide to deviate from this as you begin to get more comfortable with Redux. With that in mind, although I initially stated that the Redux docs can be a bit overwhelming, reviewing all of the different approaches taken should be viewed as a source of inspiration when it comes to creating your own setup.

Adding Redux to a React app.

So we can create our React app in the same way that we would with Create React App. Afterwards, use yarn or npm to install the following two packages:reduxandreact-reduxand then you are good to go! There is also a dev dependency calledredux-devtools-extensionwhich can be very helpful when it comes to ensuring that your Redux app is working in the way that you want it to. It is, however, optional, so don’t feel like you have to install it if you don’t want to.

We will start this by looking at the root file of our app, which ismain.js

main.js

Here we have five imports. The first two are for React, so we won’t bother discussing them, and the fifth import is simply our (App) component. The third and fourth imports are what we will focus on. The third import,Provideris basically a gateway into our Redux store (the thing we spoke about earlier). There is actually a bit more to how this works, as we need to pick which components we want to have access to our store, but we’ll discuss how that works a little later.

As you will see, we wrap ourcomponent with acomponent. One thing you will also notice from the screenshot above is that ourProvidertakes a store prop, which we pass in our (store) variable. You will see that our fourth import,configureStoreis actually a function that we have imported, and then returned the output of it to ourstorevariable, as such:const store=configureStore ();.

Now thisconfigureStorebasically, as you may have guessed, is our store configuration. This includes the initial state we want to pass in. This is a file that we actually create ourselves, and we will review this in more detail later. So in short, ourmain.jsfile imports our store and wraps our root App (component with it, thus providing access to it.)

Unfortunately there is more boilerplate required, so let’s move one step up and look at the additional code in our root (App) component:

So we have another file with five imports. The first is React, the fourth is a React component and the fifth is a css file, so let’s not bother discussing those any further. Remember how I said that there was a bit more to how we provide our components with access to our store? Well this is where our second import,connectcomes into play.

If you look at the bottom of the screenshot above , you will see that rather than exporting ourAppcomponent, we exportconnect, which is basically a curried function. A curried function is basically a function that returns another function. Whatconnectis doing here is basically taking the contents ofmapStateToPropsandmapDispatchToProps– both of which we will discuss shortly – then takes our (App) component and adds the contents ofmapStateToPropsandmapDispatchToPropsto it, then finally returns our (App) component with the new functionality added. So that’s that, but what is the contents of thosemapStateToPropsandmapDispatchToPropsthings?

(Well,mapStateToPropstakes the state from our store and passes it down as a prop for our connected (App) component. In this case, we give it the key oflistas it followed the naming convention we gave it inside of our store (more on that later). We didn’t need to follow this convention though and could have called it whatever we wanted to – either way, (list) is what we will be referring to in our app whenever we want to access that particular part of state. Now you will see thatmapStateToPropsis a function that takesstateas a parameter. In this case,stateis basically ourstoreobject (more on that later). But for your reference, if we were to put aconsole.log ('store', store)inside ofmapStateToPropslike so:

This is what the output would be:

So with that in mind, we are basically just accessing certain parts of ourstoreand we are attaching those parts to our (App) through props – in this case, we can see from the console that our state is an object calledappReducer, which contains alistarray inside of it. Therefore, we attach it to our (App) component by ourmapStateToPropsfunction returning an object with a key oflistand a value ofstate.appReducer.list. This can all seem a bit foreign and verbose at first but hopefully that has helped to break down what is going on here.

So what aboutmapDispatchToProps? Well that takes us to the third import in ourApp.jsfile, which isappActions. This is another file that we create, which we will dive into later. For now, just know thatmapDispatchToPropsis a plain object that takes the (actions) we will create and passes them into our connected (App) component as props. In Redux terms,Dispatchrefers to thedispatching of an action, which is basically a fancy way of saying that we are executing a function. SomapDispatchToPropsis kind of like saying mapFunctionsToProps, or mapActionsToProps. However, the React docs refer to this as mapDispatchToProps, so we will stick to that naming convention here.

One thing I wanted to note here is that in a typical larger React application, ourmapStateToPropsfunction might have lots of different key / value pairs inside of the object that gets returned. This could also be coming from various differentreducersfor thestorein your Redux app, as you can have access points for your store if required. The same also applies tomapDispatchToProps, in the sense that while our simple To Do app only has one file that looks after our actions –appActions– a larger app may have several files that look after actions specific to certain parts of your app. YourmapDispatchToPropsfile may pull in actions from various places and then pass them all down as props to your (App) component. Again, it’s really up to you how you choose to compose your application.

So we’ve looked at the main chunks of boilerplate that spill out from Redux into our root files, let’s now take a look at what is going on inside of our (Redux) folder, before finally taking a look at how we pull this all together inside of our React subcomponents (by this I mean anything that isn’t the rootApp.jscomponent).

The Redux folder

There is a lot to unpack here. Before we start, let’s take another look at the file structure of our app:

We will tackle this in the same order as the files appear in the screenshot above:

Actions

actions / appActions.js

So if we remember from earlier , ourappActionsfile is the file we imported into our (App.js) file. This contains the functions that carry the data (also known as payload) from our app. In the case of our To Do app, we need three pieces of functionality:

  1. Ability to hold input data
  2. Ability to add items
  3. Ability to delete items

Now the first fun ctionality –ability to hold input data– is actually going to be handled locally inside of ourToDocomponent. We could have opted to handle this ‘the Redux way’, but I wanted to demonstrate that not everything has to be handled through Redux if – in your opinion – it doesn’t make sense to do so. In this case, I wanted to simply handle input data at the component level, whilst maintaining the actual To Do list with Redux at a central level. So let’s move onto the two other functionalities required: adding and deleting items.

These functions simply take a payload. For adding new To Do items, it is likely that the payload we need to pass is the new To Do item. Therefore, our function ends up looking like this:

appActions.js

We see here that the function takes a parameter that I have opted to calltodoand returns an object that has atypeand apayload. We assign the value of thetodoparam to thepayloadkey. Now as you may have noticed from the screenshot above, thetypeshere are actually variables that have been imported from ourAC tionTypesfolder – but more on action types in a moment.

We also have ourredux_deletefunction which takes an (id) as its payload, in order for our accompanying reducer to know which To Do item to remove. Finally, we have anappActionsobject which takes ourredux_addandredux_deletefunctions as key and values. This could have also been written as:

const appActions={
redux_add: redux_add,
redux_delete : redux_delete
};

If that would have made more sense to you. I’d also like to know that all of the naming used here, such asappActionsand the prefixing of our functions withredux _is not a requirement, it was simply my own naming convention.

Action Types

actionTypes / index.js

Now you may recall from earlier that I mentioned that there is a way that our reducers and actions know how to interact with one another – this is through the use oftypes. Ourreducerswill also access these same (action types) . As you can see, these are simply variables that have a name that matches the string it is being assigned to.

This part isn ‘ t entirely necessary and you could avoid creating this file and pattern altogether if you wish. We do this, however, as a Redux best practice because it provides a central place for all of ouraction typeswhich reduces the number of places we have to go to update these if we ever need to. And given that ourreducerswill also be using these, we can be confident that the names are always correct as we are always pulling them in from one place. Speaking ofreducers

Reducers

There’s two parts here: our appReducer, and our rootReducer. In larger apps, you may have lots of different reducers. These will all then get pulled into your rootReducer. In our case, we could have just handled this with one reducer, given the small size of our app. However, I’ve opted to keep two here as you’ll likely operate in this fashion. Oh, and the names here were my convention – you can call your reducers whatever you want.

Let’s take a look at ourappReducer.

reducers / appReducer.js

The first thing we see is that we’re importing the sameaction typesthat we have been using for ouractions. The next bit is ourinitialStatevariable which is our state. This is what we will be using to initialize our store with so that we have some initial state to begin with. You may choose in your own projects to have an empty object if you do not need any initial state to begin with – again, it’s down to whatever works for your project.

The next bit is ourappReducerfunction that takes two parameters: the first is astateparam which is the state we want to begin with. In our case, we use default parameters to default the first parameter to ourinitialStateobject. This stops us from having to pass anything in further down the line. The second param is ouraction. Now thisappReducerfunction gets triggered every time one of the functions from ourappActions.jsfile is triggered – we will later see how these are triggered, but for now just know that the functions ultimately end up inside of ourToDo.jsfile. Anyway, so each time one of these functions get triggered, ourappReducerruns through a series ofswitchstatements to find the one that matches theaction.typethat was passed in. To get an idea of ​​what the data looks like that gets triggered, let’s (console.log) out ouraction, as such:

Now in our app, let’s say that we create a new To Do item by typing take out the trash “in our input field and pressing the button. When we do this, we see the following in the console:

Now besides the payload, we can see that ouractionhas atypeof"ADD _ITEM ". This matches up with theADD_ITEMvariable that ourswitchstatement has as one of its cases:

As there is a match, it executes this, which basically tells our store how its new state shou ld be. In this case, we are telling our store that the state should now equal alistarray which contains the previous contents of thelistarray, along with the newpayloadwe passed in, which if we take another look at what was logged to the console:

Now remember, theactioncarries the payload – this part is handled by theactionswe saw inappActions.js. Ourreducerspick upactionsand handle them based on whicheveraction.typematches.

Let’s now take a look at ourrootReducer

reducers / index.js

The first import we have is (combineReducers) . This is a Redux helper function which basically gathers all of your various reducers and turns them into an object which can then be passed to ourcreateStorefunction in ourstore, which we will take a look at in a moment. The second import is ourappReducerfile that we created and discussed earlier.

As mentioned earlier, we didn’t really need this step as our app is fairly simple, but I’ve decided to keep this in for learning purposes.

Store

Let’s take a look as ourconfigureStore.jsfile:

store / configureStore. JS

The first import here iscreateStorewhich holds the complete state of your app. You can only have onestore. You can have many reducers that have their owninitialStatethough. It’s key to understand the difference here though which is basically that you can have manyreducersthat provide some form of state, but you can only have onestorethat pulls in all of the data from yourreducers.

The second import here is ourrootReducer, which we have covered earlier. You will see that create a simple function calledconfigureStorethat returns ourcreateStoreimport as a function that takes in ourrootReduceras its only parameter.

Again, this is something we could have skipped and simply created out store within our rootindex.jsfile. Instead, I have kept this here as there is a lot of configuration you may find yourself doing for yourstore. This can range from setting up middleware to enabling additional Redux dev tools. It’s quite typical for this to occur, but as it would have been overkill to go into all of this now, I’ve removed anything fromconfigureStorethat wasn’t required for this app.

Okay, so we now have everything set up in ourReduxfolder, and we’ve hooked up Redux to ourindex.jsfile and our rootApp.jscomponent. Now what?

We’re on the home stretch now. We’ve set everything up and our connected components have access to our store – viamapStateToPropsand our actions viamapDispatchToProps– as (props) . We access these props just like we normally would in React, but for reference:

ToDo.js

These three props are the same ones we passed in: thelistcontains ourstate, whileredux_addandredux_deleteare our add and delete functions.

We then just use these where we need to. In our case, I have maintained the same functions that I used in ourvanillaReact app, with the exception of instead of updating state locally with some sort ofsetList ()function from auseStatehook, we call ourredux_addorredux_deletefunctions with the required payloads. Let’s take a look:

Adding items

Deleting items

Let’s take ourdeleteItemfunction and step back through each step that leads to the update of state in our app .

redux_deletetakes the ID from the To Do item that we want to remove.

If we take a look at ourappActions.jsfile, we see that the ID we passed in becomes the value of ourpayload:

appActions.js

We then see in ourappReducer.jsfile that whenever theDELETE_ITEMtype is hit in ourswitchstatement, it returns a new copy of our state that has the ID from the payload filtered out of it:

appReducer.js

As our new state is updated, the UI in our app updates.

We’ve looked at how to add Redux to a React project, how to configure a store, how to create actions that carry data, and how to create reducers that update our store. We’ve also looked at our how to connect our app up to Redux in order to enable access to all of our components. I hope you have found this useful and have gained a better understanding of how an app might look with Redux

If you’re interested in forking the styles used in this article and want to make your own equivalent piece, please feel free to do so! ***

React ToDo:https://github.com / sunil-sandhu / react-todo – 2019

Redux ToDo:https://github.com/sunil-sandhu/r edux-todo – 2019

Wondering where the app was that just used React?

Check out our previous article which compares the exact same app created in React and Vue

Wondering where the Redux and Vuex comparison is?

We’re on it!

Brave Browser
Read More
Payeer

What do you think?

Leave a Reply

Your email address will not be published. Required fields are marked *

GIPHY App Key not set. Please check settings

France 1-1 Turkey: World championships held in Paris – BBC News, BBC News

France 1-1 Turkey: World championships held in Paris – BBC News, BBC News

Google Pixel 4 leaks on UK retailer’s site, confirming three color options – GSMArena.com news – GSMArena.com, Gsmarena.com

Google Pixel 4 leaks on UK retailer’s site, confirming three color options – GSMArena.com news – GSMArena.com, Gsmarena.com