AJ_*_*AJ_ 8 javascript http-headers reactjs react-redux
我创建了一个react-redux应用程序.目前它所做的是从服务器(api)加载课程,并将它们显示到课程组件.这非常有效.我正在尝试添加一个功能,您可以通过将其发布到服务器来创建课程,然后服务器将成为成功对象.但是,当我发布到服务器时,我得到以下错误(见下文).我认为这是由于我的connect语句监听加载课程操作.显然它认为应该得到一些东西,而不是成功对象.我已经尝试了一些东西来听它们的课程和成功的反应,但是为了节省你阅读我所做的所有奇怪事情的时间,我无法让它发挥作用.任何人都知道如何解决这个问题?
错误
TypeError: this.props.courses.map is not a function
Run Code Online (Sandbox Code Playgroud)
course.component.js
onSave(){
// this.props.createCourse(this.state.course);
this.props.actions.createCourse(this.state.course);
}
render() {
return (
<div>
<div className="row">
<h2>Couses</h2>
{this.props.courses.map(this.courseRow)}
<input
type="text"
onChange={this.onTitleChange}
value={this.state.course.title} />
<input
type="submit"
onClick={this.onSave}
value="Save" />
</div>
</div>
);
}
}
// Error occurs here
function mapStateToProps(state, ownProps) {
return {
courses: state.courses
};
}
function mapDispatchToProps(dispatch) {
return {
actions: bindActionCreators(courseActions, dispatch)
};
}
export default connect(mapStateToProps, mapDispatchToProps)(Course);
Run Code Online (Sandbox Code Playgroud)
course.actions.js
export function loadCourse(response) {
return {
type: REQUEST_POSTS,
response
};
}
export function fetchCourses() {
return dispatch => {
return fetch('http://localhost:3000/api/test')
.then(data => data.json())
.then(data => {
dispatch(loadCourse(data));
}).catch(error => {
throw (error);
});
};
}
export function createCourse(response) {
return dispatch => {
return fetch('http://localhost:3000/api/json', {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify({
response: response
})
})
.then(data => data.json())
.then(data => {
dispatch(loadCourse(data));
}).catch(error => {
throw (error);
});
};
}
Run Code Online (Sandbox Code Playgroud)
course.reducer.js
export default function courseReducer(state = [], action) {
switch (action.type) {
case 'REQUEST_POSTS':
return action.response;
default:
return state;
}
}
Run Code Online (Sandbox Code Playgroud)
server.js
router.get('/test', function(req, res, next) {
res.json(courses);
});
router.post('/json', function(req, res, next) {
console.log(req.body);
res.json({response: 200});
});
Run Code Online (Sandbox Code Playgroud)
我已经尝试添加对状态的响应,并在地图状态中监听它到道具,但仍然出于某种原因反应是试图将响应映射到课程.我需要第二种连接方法吗?
function mapStateToProps(state, ownProps) {
return {
courses: state.courses,
resposne: state.resposne
};
}
Run Code Online (Sandbox Code Playgroud)
从图片中可以看出,响应被映射为课程而不是响应.
Link incase stack不会显示它.课程:https://ibb.co/jva1YQ
回复:https: //ibb.co/eZYif5
假设:
state.courses最初是一个空数组 - 来自 course.reducer.jsfetchCourses()第一次渲染视图时不会调用操作fetchCourses()也没有问题,只要coursesserver.js 中是一个数组(响应中的数组替换了初始的state.courses)流程:
现在我假设第一次渲染成功并且 React 显示<input type="text">和submit按钮。现在,当您输入标题并单击submit按钮时,该onSave()方法会触发createCourse()带有或多或少类似于 的参数的操作{ title: 'something' }。
然后,序列化上述参数并发送到服务器(在 course.actions.js -> 中createCourse()),服务器又返回一个类似于{response: 200}(在 server.js 中)的响应。响应字段是一个整数而不是一个数组!更进一步,您可以使用触发in course.reducer.js 的loadCourses()对象进行调用{response: 200}courseReducer
将(根据假设为 [])courseReducer() 替换为整数。 state.courses此状态更新会触发重新渲染,您最终会调用map()整数而不是数组,从而导致TypeError: this.props.courses.map is not a function.
可能的解决方案:
course调用端点的对象),或者state.courses数组中,例如,return [...state, action.response]根据OP的评论,如果您想要做的是将新课程对象发送到服务器,验证它并发送成功(或错误),并根据响应将相同的课程对象添加到之前的课程列表中,那么您可以简单地在减速器中使用与 and (如上所述)调用的loadData()同一course对象进行调用,而不是替换或改变旧数组,而是创建一个新数组并将课程对象附加到其中,在 es6 中,您可以执行类似的操作。createCourse()return [...state, course]
我建议你阅读Redux 的 Doc。引用Redux Actions 的文档
操作是将数据从应用程序发送到商店的信息负载。它们是商店的唯一信息来源。
使用或多或少类似于 的有效负载createCourse()调用该操作,然后使用 AJAX 请求调用服务器并将有效负载传递给服务器,然后服务器验证有效负载并发送基于成功(或错误)的响应根据你的逻辑。服务器响应看起来像,。至此,行动结束。现在,您从服务器内部收到响应,这不是您想要的(基于您的评论)。因此,尝试像这样执行操作(尝试重命名参数,这有点令人困惑)
{title: 'Thing you entered in Text Field'}{response: 200}createCourse()dispatch() loadCourses()createCorse()dispatch()response
//.....
.then(data => {
dispatch(loadCourse(response)); // the same payload you called createCourse with
})
//.....
Run Code Online (Sandbox Code Playgroud)
现在,loadCourse()这是一个非常基本的操作,它只是转发参数,Redux 使用它来调用您的reducer. 现在,如果您遵循前面的讨论并更新了您的 call 方式loadCourse(),那么返回看起来loadCourse()像
{
type: REQUEST_POSTS,
response: {
title: 'Thing you entered in Text Field',
}
}
Run Code Online (Sandbox Code Playgroud)
然后传递给你的reducer,特别是你的courseReducer()。
操作描述了发生了某些事情的事实,但不指定应用程序的状态如何响应而变化。这是减速器的工作。
必须reducer定义有关操作应如何影响 内数据的逻辑store。
在你的 中courseReducer(),你只需返回对象response内的字段action,并且 [期望] Redux 会自动神奇地改变你的状态!不幸的是,这不是发生的事情:(
无论你从减速器返回什么,都会完全替换之前存在的任何东西/对象,就像,如果你的状态看起来像这样
{ courses: [{...}, {...}, {...}] }
Run Code Online (Sandbox Code Playgroud)
然后你从你的减速器返回这样的东西
{ title: 'Thing you entered in Text Field'}
Run Code Online (Sandbox Code Playgroud)
然后 redux 会将状态更新为如下所示
{ courses: { title: 'Thing you entered in Text Field'} }
Run Code Online (Sandbox Code Playgroud)
state.courses 不再是数组!
解决方案:
将您的减速机更改为这样的
export default function courseReducer(state = [], action) {
switch (action.type) {
case 'REQUEST_POSTS':
return [...state, action.response]
default:
return state
}
}
Run Code Online (Sandbox Code Playgroud)
旁注:这有时可能会令人困惑,因此为了记录起见,state里面courseReducer()不是完整的状态,而是管理的property状态。您可以在这里阅读更多相关内容statereducer