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:
import React from 'react';
import ReactDOM from 'react-dom';
import { createStore } from 'redux';
import {Provider, connect} from 'react-redux';
We added two more things here the Provider component and the connect hoc.
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;
}
}
var store = createStore(changeState);
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
class Home extends React.Component {
render() {
return (
<Provider store={store}>
<Comp1 /><br />
<Comp2 />
</Provider>
)
}
}
Ok, your Fragment is gone, I'm sorry about that, but it's now no longer necessary. Fragments are used to return two or more components, but since the Provider is now wrapping the components, there is no need to use a Fragment.
And about the Provider, you just need to put it outside of everything and give it your store. Easy enough.
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>
)
}
}
In this last component we didn't move anything. Although we should have, look how you're using your store directly to dispatch your action. In a normal app, this component would be in another file, so you wouldn't have access to the store property. And here comes again our friend connect which helps us dispatch actions through a function called mapDispatchToProps 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:
class Comp2 extends React.Component {
render() {
return (
<div>
<h1>Total items in cart: {this.props.qty}</h1>
<h1>Total price of cart :{this.props.price}</h1>
</div>
)
}
}
function mapStateToProps( state ){
return { qty: state.qty, price:state.price }
}
Comp2 = connect(mapStateToProps)(Comp2);
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 our mapStateToProps method and then our component. And they mated inside connect 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.