I am learning redux and I have put up a simple code which uses the store, action and reducer. I am using store.subscribe() to listen for changes in the state and using it to update my local state.
Below is my entire code in index.js:
import React from 'react';
import ReactDOM from 'react-dom';
import { createStore } from 'redux';
var store = createStore(changeState);
var initialState = {
qty: 0,
price: 0
}
function changeState(state = initialState, action) {
switch (action.type) {
case 'INCREMENT':
var stateCopy1 = Object.assign({}, state);
stateCopy1.qty = stateCopy1.qty + action.qty;
stateCopy1.price = stateCopy1.price + action.price;
return stateCopy1;
default:
return state;
}
}
class Home extends React.Component {
render() {
return (
<React.Fragment>
<Comp1 /><br />
<Comp2 />
</React.Fragment>
)
}
}
class Comp1 extends React.Component {
increase = () => {
var action = {
type: 'INCREMENT',
qty: 1,
price: 100
}
store.dispatch(action);
}
render() {
return (
<button type="button" onClick={this.increase}>Increase</button>
)
}
}
class Comp2 extends React.Component {
constructor() {
super();
this.state = {
cartQty: 0,
cartPrice: 0
}
}
render() {
store.subscribe(() => {
var globalState = store.getState();
this.setState({cartQty:globalState.qty,cartPrice:globalState.price});
})
return (
<div>
<h1>Total items in cart: {this.state.cartQty}</h1>
<h1>Total price of cart :{this.state.cartPrice}</h1>
</div>
)
}
}
ReactDOM.render(<Home />, document.getElementById('root'));
I want to use react-redux to avoid the local state and subscription. I read about connect() and mapStateToProps() and . But I am unable to figure out how to use them in my below code. How can I implement these parts in my code?
First, you want to develop a project thats more modular as you move along in your learning curve, it will be easier for you.
So set up a
src/index.js
, you already have anindex.js
file I am saying make that your rootindex.js
and then refactor it like so:So
Provider
is at the top of the hierarchy and having implementedProvider
you will then be able to utilize theconnect()
function, otherwise you will get an error.Before we go ahead and implement
connect()
though, lets move down the hierarchy, hierarchy very important in React-Redux.Provider-> App -> child components.
So next up is
components/App.js
:So let's assume that you are wanting to wire up
connect()
to yourHome
component, I don't think you specified, but this is what it would look like:You didn't talk much about your action creator or your details about your data so I am just making it about collecting a list of Homes since you have a
Home
component. So above I imported theconnect()
function inside the component and then below I implement it. Pay attention to the fact that I have placed anull
where yourmapStateToProps
will eventually be. Again, you did not go into details about your state so if I were setting this up for you,null
is sufficient to get your app working until you are ready to implementmapStateToProps
, but actions you do need so I created thatfetchLocations
action and implemented insideconnect()
.For your reducers you can do
reducers/locationsReducer.js
:And then implement it with your combined reducer like so,
reducers/index.js
:I believe you now have a functioning React-Redux application and you should be able to take it away from there.
Below is what you need to do, i have given an example with comp1 Component, also check this link https://redux.js.org/basics/usage-with-react helps to get more information.
Code
There is for theoretical reference of how to use redux and react-redux based on your example. This should give you idea of how to use both and with little google help you can finish your example I guess.
Of course you can, first let's make sure concepts are clear.
Redux already has a 'state', so you copying it to your internal state is redundant.
connect()
:This convenience method is used to map the redux's state, to props in your component. That is, you're not copying the state into another state, you use Redux's state as props, which are inmutable and more like a reference to the real data inside Redux.
It's built with a pattern call hoc, but that's a lesson for another question. The important thing to know about a hoc is that it takes a component as an argument and it returns a new component, an improved one.
mapStateToProps()
:This will be your way into telling
connect
what part of redux's state you want to get inside your component. It's a method that receives the complete redux's state, extracts the properties you want to use, and returns them to be sent as props to your component.Now you're missing one key part of the ecuation here, which is redux's...
Provider
:This piece should wrap all of your app ( or the part of it that you want it to has redux access, which usually is all of it ) and is the one in charge of sending redux's store down the tree so
connect
can grab it later ( This is achieved through react's context, but that's a meal for another date ).You get your provider like:
import {Provider} from 'react-redux';
and then you give it the store as a prop called....store
(clever right?)Enough chit chat right, let's get down to business.
We start with the imports, let's get everything we need:
We added two more things here the
Provider
component and theconnect
hoc.Now, you saw what happened there? Exactly! Nothing. Your reducer can remain as is, we are not moving that, although for a larger app you may want to learn to combine reducers
Ok, your
Fragment
is gone, I'm sorry about that, but it's now no longer necessary.Fragment
s are used to return two or more components, but since theProvider
is now wrapping the components, there is no need to use aFragment
.And about the
Provider
, you just need to put it outside of everything and give it yourstore
. Easy enough.In this last component we didn't move anything. Although we should have, look how you're using your
store
directly todispatch
youraction
. In a normal app, this component would be in another file, so you wouldn't have access to thestore
property. And here comes again our friendconnect
which helps us dispatch actions through a function calledmapDispatchToProps
you read about it here, but that's also for another day.And here it comes, what we all were waiting for, the
connect
method:This may be a little bit confusing, so let me explain:
First, we removed everything related to your component's state. We're not using it anymore, cause that's what you wanted right? And also the component is now leaner. And cooler.
But what happened later? well, first we are defining the
mapStateToProps
function. And this is translating redux's state to your components state. This time, we sending every single property from redux's state to your component, but in a bigger app this would not be the case, in a bigger app redux would have the state of everything inside, that could be the cart items, the app theme colors, the user's info etc etc. A lot of things, so inside this function we select only the properties we are interested in getting inside our component.Now the connect call... we are redefining our component, and it's kinda weird, but I'll try to explain.
connect
received ourmapStateToProps
method and then our component. And they mated insideconnect
and gave birth to another component, this one is a component that will have the component we defined first as a child, and will always send it the parts of the redux's state we asked for as props.use Provider from react-redux and your store will be available to all your child components
There are few things that you need to take care of.
First, you need to have a react-redux installed and then use Provider component at the top level to which you pass store
Second: You need to connect the components that need to access
store
ordispatch
Third: You need to render the connected components
Fourth: You need
mapStateToProps
to be passed to container which access state andmapDispatchToProps
to accesses dispatch or make action creators available as props to components. In case you do not passmapDispatchToProps
toconnect
, by defaultdispatch
prop is made available to the component. You can look at the API docs hereFifth Create store after defining changeState reducer and initialState
Working demo