Reputation: 33
I am attempting to populate a dropdown list from the server in a React/Redux project. The dropdown list in defined as a component and embedded in a parent component.
Parent component:
import React from 'react';
import Form from 'components/Form';
import { reduxForm } from 'redux-form';
import { Input } from 'components';
import FirstFormList from '../FirstFormList/FirstFormList.js';
import { firstform } from 'redux/modules/firstForm';
class FirstForm extends Form {
render() {
const {
fields: { dateTime }
} = this.props;
return (
<form onSubmit={this.handleApiSubmit(firstform)} className="form-horizontal">
{this.renderGlobalErrorList()}
<Input field={dateTime} label="Time Stamp" />
<div className="form-group">
<div className="col-md-1" />
<label htmlFor="select1" className="col-md-1">Select Option</label>
<div className="col-md-10">
<FirstFormList />
</div>
</div>
<div className="form-group">
<div className="col-md-offset-2 col-md-10">
<button type="submit" className="btn btn-default">Submit</button>
</div>
</div>
</form>
);
}
}
FirstForm = reduxForm({
form: 'firstform',
fields: ['dateTime']
}
)(FirstForm);
export default FirstForm;
The child component FirstFormList
import React from 'react';
import { connect } from 'react-redux';
import { fetchfirstformlist } from 'redux/modules/firstFormList';
class FirstFormList extends React.Component {
constructor(props) {
super(props);
this.state = {
items: []
};
}
componentDidMount() {
this.props.fetchfirstformlist();
}
render() {
let optionItems = [];
if (this.props.items !== undefined && this.props.items !== null) {
const items = this.props.items;
optionItems = items.map((item) =>
<option key={item.value}>{item.label}</option>
);
}
return (
<div>
<select className="form-control">
{optionItems}
</select>
</div>
);
}
}
export default connect(
state => ({ items: state.items }),
{ fetchfirstformlist })(FirstFormList);
The child component reducer:
export const FIRSTFORMLISTFETCH_START = 'react/firstform/FIRSTFORMGETLIST_START';
export const FIRSTFORMLISTFETCH_COMPLETE = 'react/firstform/FIRSTFORMGETLIST_COMPLETE';
export const FIRSTFORMLISTFETCH_ERROR = 'react/firstform/FIRSTFORMGETLIST_ERROR';
const initialState = {
};
export default function reducer(state = initialState, action = {}) {
switch (action.type) {
case FIRSTFORMLISTFETCH_COMPLETE:
return {
...state,
items: action.result.items
};
default:
return state;
}
}
export function fetchfirstformlist() {
return {
types: [FIRSTFORMLISTFETCH_START, FIRSTFORMLISTFETCH_COMPLETE, FIRSTFORMLISTFETCH_ERROR],
promise: (client) => client.post('/api/firstform/getfirstformlist')
};
}
After the componentDidMount fires can see the items returned by the server in the state if I set a break point in the FirstFormList compoenent:
export default connect(
state => ({ items: state.items }),
{ fetchfirstformlist })(FirstFormList);
However the render() of the component does not fire after the items are attached to the state.
Upvotes: 0
Views: 1081
Reputation: 33
I found the problem. The list items are stored in the state in state.firstFormList.items not state.items. The export should be:
export default connect(
state => ({ items: state.firstFormList.items }),
{ fetchfirstformlist })(FirstFormList);
not
export default connect(
state => ({ items: state.items }),
{ fetchfirstformlist })(FirstFormList);
Upvotes: 0
Reputation: 1186
Ok, the state in export default connect(state => ({ items: state.items }),{ fetchfirstformlist})(FirstFormList);
is the reducer state, it is not React state. So you can remove this.state = {items: []};
as you are not using this.state.items
in your render.
You are getting the this.props.items
from the connect
state.items
.
Secondly, are you checking the logs to see if there are errors in the reducers. (I guess if action.result
is undefined
it will throw an error on action.result.items
). So can you check that action.result is not undefined or assign it a default value before you try to use action.result.items? You should also try to comment out lines like the one with the promise and see if it works. The line with the multiple types also looks suspicious.
Also, you can try adding curly braces to your one liner anonymous methods and add additional logging and explicly return values.
Also, the way react lifecycles work is that the constructor is called only the first time a component renders and then the componentDidMount is also called only the first time the component renders.
Thirdly, why don't you debug the state of redux using the redux plugin
or by {console.log("test", this.props)}
in your render method and in your reducer. This way you will definitely find out where the error is since the information provided may not be sufficient.
If these 3 steps don't fix your answer or help you resolve it leave a comment and I'll help you.
Upvotes: 1