React - TypeError:this.props.courses.map不是函数

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

riy*_*ali 3

假设:

  1. state.courses最初是一个空数组 - 来自 course.reducer.js
  2. fetchCourses()第一次渲染视图时不会调用操作
  3. 即使你调用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.

可能的解决方案:

  1. 从serve.js 返回一个有效的响应(即返回course调用端点的对象),或者
  2. 更新您的减速器以将新的课程对象添加到现有state.courses数组中,例如,return [...state, action.response]

更新:

根据OP的评论,如果您想要做的是将新课程对象发送到服务器,验证它并发送成功(或错误),并根据响应将相同的课程对象添加到之前的课程列表中,那么您可以简单地在减速器中使用与 and (如上所述)调用的loadData()同一course对象进行调用,而不是替换或改变旧数组,而是创建一个新数组并将课程对象附加到其中,在 es6 中,您可以执行类似的操作。createCourse()return [...state, course]

更新2:

我建议你阅读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()

再次引用ReduxReducers 的文档

操作描述了发生了某些事情的事实,但不指定应用程序的状态如何响应而变化。这是减速器的工作。

必须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