Jayce444 Jayce444 - 1 month ago 23
React JSX Question

Redux - reducer not getting called

I'm trying to learn Redux. I followed an online tutorial and used their example and it worked fine. Then I made another small test app and it worked fine. Now I'm trying another small test app and I'm stuck on this error and have no idea why.

The app is simply a input box and a button, and when you click the button it adds whatever's in the box to a list that is displayed below.

However, the reducer isn't updating the state. I've looked at the common problems that cause this and can't seem to find those errors in mine, my reducer doesn't change the state and I've bound the dispatch and so on. Maybe I've just mispelled something somewhere (or something small and stupid like that) but I just can't get it working.

So I tried to change it so that it just displays whatever you type in the box below and it STILL doesn't work. Anyone know why the reducer isn't activating?

index.js (main)

import 'babel-polyfill';
import React from 'react';
import ReactDOM from 'react-dom';
import {Provider} from 'react-redux';
import {createStore, applyMiddleware} from 'redux';
import thunk from 'redux-thunk';
import promise from 'redux-promise';
import createLogger from 'redux-logger';
import allReducers from './reducers';
import App from './components/App';

const logger = createLogger();
const store = createStore(
allReducers,
applyMiddleware(thunk, promise, logger)
);

ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById('root')
);


App.js

import React from 'react';
import NameList from '../containers/name-list.js'
import Input from '../containers/input.js'

const App = () => (
<div>
<Input />
<hr />
<NameList />
</div>
);

export default App;


index.js (action)

export const addName = (name) => {
return {
type: 'NAME_ADDED',
payload: name
}
};


reducer-add-name.js

export default function (state = null, action) {
switch (action.type) {
case 'NAME_ADDED':
return action.payload;
break;
}
return state;
}


index.js (reducer combiner)

import {combineReducers} from 'redux';
import AddNameReducer from './reducer-add-name';


const allReducers = combineReducers({
nameList: AddNameReducer
});

export default allReducers


input.js

import React, {Component} from 'react';
import {bindActionCreators} from 'redux';
import {connect} from 'react-redux';
import {addName} from '../actions/index'

class Input extends Component {
render() {
return(
<div>
<input id='name-input' />
<button id='add-name-button' onClick={() => addName(document.getElementById('name-input').value)}>Add name</button>
</div>
);
}
}

function mapStateToProps(state) {
return {
nameList: state.nameList
};
}

function matchDispatchToProps(dispatch) {
return bindActionCreators({addName: addName}, dispatch);
}

export default connect(mapStateToProps, matchDispatchToProps)(Input);


name-list.js

import React, {Component} from 'react';
import {bindActionCreators} from 'redux';
import {connect} from 'react-redux';

class NameList extends Component {

getNameList() {
//This is where I'll loop through this.props.nameList and build the list of elements
return this.props.nameList;
}

render() {
return(
<div>Current list : {this.getNameList()}</div>
);
}
}

function mapStateToProps(state) {
return {
nameList: state.nameList
};
}

export default connect(mapStateToProps)(NameList);


Thanks for any help!

Answer

I think your action hasn't been dispatched.

In your input.js On button tag, change

onClick={() => addName(document.getElementById('name-input').value)}

to

onClick={() => this.props.addName(document.getElementById('name-input').value)}

Thing is action should be passed through mapDispatchToProps and 'bindActionCreators(actions, dispatch)' will wrap your action with 'dispatch', and pass through your component via props 'addName'. (as defined in your mapDispatchToProps)

An action alone is like a bullet (just return object) you will need something to fire it (dispatch)

In your case

import {addName} from '../actions/index' <--- a bullet

has been declared and your onClick, without dispatch, it would only return a mere object, not dispatching it to reducer.

addName() // <--- Just a bullet

But

this.props.addName() // <--- bullet with a gun

is from mapDispatchToProps / bindActionCreators... it has dispatch() wrapped around, that is the one we would use.