我无法在构造函数中获得使用redux概念实现的道具。
容器组件代码
class UpdateItem extends Component{
constructor(props) {
super(props);
console.log(this.props.item.itemTitle) // output: undefined
this.state = {
itemTitle: this.props.item.itemTitle,
errors: {}
};
this.handleChange = this.handleChange.bind(this);
}
handleChange(e) {
//If the input fields were directly within this
//this component, we could use this.refs.[FIELD].value
//Instead, we want to save the data for when the form is submitted
let state = {};
state[e.target.name] = e.target.value.trim();
this.setState(state);
}
handleSubmit(e) {
//we don't want the form to submit, so we pritem the default behavior
e.preventDefault();
let errors = {};
errors = this._validate();
if(Object.keys(errors).length != 0) {
this.setState({
errors: errors
});
return;
}
let itemData = new FormData();
itemData.append('itemTitle',this.state.itemTitle)
this.props.onSubmit(itemData);
}
componentDidMount(){
this.props.getItemByID();
}
componentWillReceiveProps(nextProps){
if (this.props.item.itemID != nextProps.item.itemID){
//Necessary to populate form when existing item is loaded directly.
this.props.getItemByID();
}
}
render(){
let {item} = this.props;
return(
<UpdateItemForm
itemTitle={this.state.itemTitle}
errors={this.state.errors}
/>
);
}
}
UpdateItem.propTypes = {
item: PropTypes.array.isRequired
};
function mapStateToProps(state, ownProps){
let item = {
itemTitle: ''
};
return {
item: state.itemReducer
};
}
function mapDispatchToProps (dispatch, ownProps) {
return {
getItemByID:()=>dispatch(loadItemByID(ownProps.params.id)),
onSubmit: (values) => dispatch(updateItem(values))
}
}
export default connect(mapStateToProps,mapDispatchToProps)(UpdateItem);
在render()方法中,我可以从redux获取道具,即物品,但不能在构造函数内部。
用于查看redux实现是否正确的操作的代码,
export function loadItemByID(ID){
return function(dispatch){
return itemAPI.getItemByID(ID).then(item => {
dispatch(loadItemByIDSuccess(item));
}).catch(error => {
throw(error);
});
};
}
export function loadItemByIDSuccess(item){
return {type: types.LOAD_ITEM_BY_ID_SUCCESS, item}
}
最后我的reducer如下所示,
export default function itemReducer(state = initialState.item, action) {
switch (action.type) {
case types.LOAD_ITEM_BY_ID_SUCCESS:
return Object.assign([], state = action.item, {
item: action.item
});
default:
return state;
}
}
我用谷歌搜索得到没有运气的答案,我不知道我犯了什么错误。如果有人指出我这将是一个很大的帮助。提前谢谢。
答案 0 :(得分:4)
您无法在构造函数中访问props的原因是它在首次安装组件之前只调用一次。
在componentWillMount
函数中调用加载项的操作,该函数在调用构造函数后发生。
您似乎试图在mapStateToProps
功能中设置默认值,但根本没有使用它
function mapStateToProps(state, ownProps){
// this is never used
let item = {
itemTitle: ''
};
return {
item: state.itemReducer
};
}
我注意到的下一部分是你从redux获取状态并尝试将其注入组件的本地状态
this.state = {
itemTitle: this.props.item.itemTitle,
errors: {}
};
混合redux状态和组件状态很少是一个好主意,应该尽量避免。它可能导致不一致,并且很难发现错误。
在这种情况下,我发现没有任何理由可以将this.state.itemTitle
的所有用法替换为this.props.items.itemTitle
,并将其从组件状态中完全删除。
你的代码有一些特殊的东西让我很难推断代码背后的意图。
首先是减速器
export default function itemReducer(state = initialState.item, action) {
switch (action.type) {
case types.LOAD_ITEM_BY_ID_SUCCESS:
return Object.assign([], state = action.item, {
item: action.item
});
default:
return state;
}
}
您还没有显示initialState
对象,但通常它代表减速器的整个初始状态,因此使用initialState.item
对我来说非常突出。你可能正在为所有的reducers重用一个共享的初始状态对象,所以我不太关心这个。
Object.assign
电话是多么令人困惑。我不确定它的目的是在状态中输出替换item
的对象,或者是要将action.item
附加到数组,还是要将一个数组作为单个项目由此产生的状态。 state = action.item
部分对于其在行动中的意图也特别令人费解。
PropTypes
UpdateItem
要求item
成为数组
UpdateItem.propTypes = {
item: PropTypes.array.isRequired
};
但是组件中的用法将其视为对象
this.state = {
// expected some kind of array lookup here |
// V---------------
itemTitle: this.props.item.itemTitle,
errors: {}
};
Here is a example我在评论中谈论的内容。它是您的代码的简化版本(我没有所有组件。我还修改了一些符合我个人风格的东西,但希望您仍然可以看到它的内容上。