Reputation: 1263
This is my index (App component) file:
const mapStateToProps = (state, ownProps = {}) => {
console.log('this is from statetoprops: ', state); // state
console.log('from state to props, own Props: ', ownProps); // undefined
return {
myValue: state,
};
};
const AppWrapper = styled.div`
max-width: calc(768px + 16px * 2);
margin: 0 auto;
margin-top: 64px;
display: flex;
min-height: 100%;
padding: 0 16px;
flex-direction: column;
`;
class App extends React.Component {
render() {
return (
<div>
<Header />
<AppWrapper>
<Switch>
<Route exact path="/main/" component={HomePage} />
<Route path="/main/aboutme" component={AboutMe} />
<Route path="/main/models" component={Models} />
<Route path="/main/landscapes" component={Landscapes} />
</Switch>
</AppWrapper>
{console.log(`This is the component App props: ${this.props.myValue}`)}
<Footer />
</div>
);
}
}
export default connect(mapStateToProps)(App);
The console log of this.props.myValue is:
This is the component App props: Map { "route": Map { "location": Map { "pathname": "/main", "search": "", "hash": "", "state": undefined, "key": "gftdcz" } }, "global": Map { "myValue": 0 }, "language": Map { "locale": "en" } }
If I do this.props.myValue.global, I get undefined. I need to access and manipulate the myValue value.
This is the reducer:
import { fromJS } from 'immutable';
// The initial state of the App
const initialState = fromJS({
myValue: 0,
});
function appReducer(state = initialState, action) {
console.log(`The reducer is being found and here is the state: ${state}`, ' and the action: ', action);
switch (action.type) {
case 'Name':
return {
myValue: action.payload,
};
default:
return state;
}
}
export default appReducer;
And this is the global reducer file...
/**
* Combine all reducers in this file and export the combined reducers.
*/
import { fromJS } from 'immutable';
import { combineReducers } from 'redux-immutable';
import { LOCATION_CHANGE } from 'react-router-redux';
import globalReducer from 'containers/App/reducer';
import languageProviderReducer from 'containers/LanguageProvider/reducer';
/*
* routeReducer
*
* The reducer merges route location changes into our immutable state.
* The change is necessitated by moving to react-router-redux@5
*
*/
// Initial routing state
const routeInitialState = fromJS({
location: null,
});
/**
* Merge route into the global application state
*/
function routeReducer(state = routeInitialState, action) {
switch (action.type) {
/* istanbul ignore next */
case LOCATION_CHANGE:
return state.merge({
location: action.payload,
});
default:
return state;
}
}
/**
* Creates the main reducer with the dynamically injected ones
*/
export default function createReducer(injectedReducers) {
return combineReducers({
route: routeReducer,
global: globalReducer,
language: languageProviderReducer,
...injectedReducers,
});
}
I'm using a react/redux boilerplate and I'm trying to learn redux at the same time so it's an interesting experience. I'm hoping someone can point me in the right direction here.
Upvotes: 0
Views: 1299
Reputation: 8662
You're setting this.props.myValue
to the entire contents of the Redux store, when it looks like you want to select one specific value.
mapStateToProps
receives the entire store state, not just the chunk from one specific reducer. So you need to first access the state from the specific reducer you want. For this reason, in many examples of mapStateToProps
, the first line uses destructuring to get the relevant the piece of state, like this:
const { global } = state;
Note - this gives you a variable named global
which is going to be very confusing to anyone reading your code. In JS the "global context" is a commonly used term; though this probably won't break anything, it's not good for readability. See below for a suggestion about your variable names.
And from that subset of the root state, you want just the myValue
property.
So your mapStateToProps should look like this:
const mapStateToProps = (rootState) => { // renamed from state to rootState - this does not change the behavior, just more accurately describes what will be passed in
const { global } = rootState;
return {
myValue: global.myValue,
};
};
This could also be more concisely written as
const mapStateToProps = (rootState) => ({ myValue: rootState.global.myValue});
Since your state is an Immutable map, as far as I know destructuring won't work. So in your mapStateToProps you'll have to do something like:
const global = rooState.get('global');
const myValue = global.get('myValue');
Your code uses the reducer name global
for the reducer that is called appReducer
inside its own code file. And that reducer isn't the root reducer, so there's nothing "global" about it. The term "global" doesn't really mean anything in the context of the redux store - although the term "root" does.
It will help reduce confusion (for others reading your code, and probably for yourself too) if you avoid using the term global for anything, and match up your reducer names in the root reducer with the name of the file the reducer is defined in (or the name it is given inside its code file). So I suggest using the name app
instead of global
in your combineReducers
call. Even better would be to name it to something more meaningful, although I get that you are in the proof-of-concept stage here.
Upvotes: 1
Reputation: 68
It is a little hard to know exactly what is going wrong with your code without running it, but a few things stand out to me:
console.log(this.props.myValue)
, you get what looks to be a JavaScript object.My first instinct is that your action.payload
is not a plain JavaScript object, but is actually a string (or potentially some other type of object).
One quick way to test this would be to console.log(this.props.myValue.constructor)
.
Upvotes: 0