Reputation: 23
So I'm extremely new to Redux (this is my first project using it) and I've run into a bit of a roadblock.
What I have here is a simple scenario in which an input value changes, updating the Redux store onChange. Here's a look at my code:
The component:
import React from 'react';
import { connect } from 'react-redux';
import { setSuperhero } from '../actions/setSuperhero'
const SearchField = (props) => (
<div className="d-flex justify-content-center">
<form className="form-inline">
<div className="form-group mb-0">
<input
type="text"
name="superhero"
className="form-control"
placeholder="Thor, Iron Man, etc."
onChange={(e) => {
props.dispatch(setSuperhero(e.target.value));
}}></input>
</div>
<button type="submit" className="btn btn-light ml-2">Search</button>
</form>
</div>
)
const mapStateToProps = state => {
return {
superhero: state.superhero.name
}
}
export default connect(mapStateToProps)(SearchField);
The action:
import * as types from '../types';
export const setSuperhero = name => dispatch => (
dispatch({
type: types.SET_SUPERHERO,
payload: name
})
)
The types:
export const SET_SUPERHERO = "SET_SUPERHERO";
The reducer:
import * as types from '../types'
const superheroReducer = (state = {name: 'Thor'}, action) => {
switch (action.type) {
case types.SET_SUPERHERO: {
return {
...state,
name: action.payload
}
}
default:
return state;
}
}
export default superheroReducer
Logger indicates that the action is sent, the state just doesn't update with the value provided. I've tried looking at immutability. I've tried making sure my Provider is set up properly (it does). I've used and deleted 'mapDispatchToProps' about 100 times. I've looked through every recommended question on this board for an answer and still come I'm coming up empty. For whatever reason, this stupid thing just won't update.
Any help at all would be immensely appreciated.
EDIT: As requested, here's the code for my root reducer:
import { combineReducers } from 'redux';
import uiReducer from './uiReducer';
import superheroReducer from './superheroReducer';
import heroInfoReducer from './heroInfoReducer';
import comicsReducer from './comicsReducer';
import seriesReducer from './seriesReducer';
import eventsReducer from './eventsReducer';
const rootReducer = combineReducers({
ui: uiReducer,
superhero: superheroReducer,
heroInfo: heroInfoReducer,
comics: comicsReducer,
series: seriesReducer,
events: eventsReducer
})
export default rootReducer
EDIT: Quick addendum on accepted answer: was calling 'thunk' AND 'promise' in my 'applyMiddleware' call. Removing 'promise' fixed the issue, but ultimately the problem was that I was passing in a function to my dispatch call. Thank you everyone!
Upvotes: 2
Views: 2979
Reputation: 12746
Here everything looks correct except
1. setSuperhero
action is returning a function which is incorrect. It should return a plain object. Quoting from the redux documentation
Actions are plain JavaScript objects. Actions must have a type property that indicates the type of action being performed.
So you need to change
export const setSuperhero = name => dispatch => (
dispatch({
type: types.SET_SUPERHERO,
payload: name
})
)
to
export const setSuperhero = name => ({
type: types.SET_SUPERHERO,
payload: name
});
2. You have not included the createStore
part in the question. So if you want to access the subtree of state then you must register reducer at that tree using the combineReducers
e.g. Here you want to access your state value at state.superhero
. So you must register your reducer as such
import { createStore, combineReducers } from "redux";
import reducers from "./reducer";
const store = createStore(combineReducers({ superhero: reducers }));
export default store;
Now you can access it as state.superhero
. If you don't want to use the combineReducers
and just register a single reducer as
const store = createStore(reducers)
then the superhero name data will be available under state.name
and not the state.superhero.name
.
Here is the working codesandbox. https://codesandbox.io/s/n445j386xp
Update:
As you have included the createStore
part in the question now, The problem is with your action. It must return a plain object, not a function. Rest looks good.
Hope, it helps :)
Upvotes: 4