AdrianDevera AdrianDevera - 1 month ago 9
React JSX Question

React Redux Reducer: 'this.props.tasks.map is not a function' error

I am making a React Redux example; however, I ran into an issue and get the error below:


TypeError: this.props.tasks.map is not a function
[Learn More]


I have tried many things and I cannot seem to understand why this is not working. I believe it is when the allReducers maps the tasks from the Tasks function. I have fixed this error back and forth but then it would complain it was undefined. I would fix that and loop back to this issue. Any help would be appreciated. Im sure I am making a simple mistake. Below are my following files

App.js


import React from 'react';
import TaskBoard from "../containers/task-board";
require('../../scss/style.scss');

const App = () => (
<div>
<h2>Task List</h2>
<hr />
<TaskBoard/>
</div>
);

export default App;





index.js



import {combineReducers} from 'redux';
import {Tasks} from './reducer-tasks';
const allReducers = combineReducers({
tasks: Tasks
});

export default allReducers





task-board.js



import React, {Component} from 'react';
import {bindActionCreators} from 'redux';
import {connect} from 'react-redux';
import {deleteTaskAction} from '../actions/ActionIndex';
import {editTaskAction} from '../actions/ActionIndex';
class TaskBoard extends Component {
renderList() {
return this.props.tasks.map((task) => {
if(task.status == "pending"){
return (<li key={task.id}>
{task.id} {task.description}
<button type="button">Finish</button>
<button type="button">Edit</button>
<button onClick={() => this.props.deleteTask(task)} type="button">Delete</button>
</li>
);
}
});
}
render() {
if (!this.props.tasks) {
console.log(this.props.tasks);
return (<div>You currently have no tasks, please first create one...</div>);
}
return (
<div>
{this.renderList()}
</div>
);
}
}
function mapStateToProps(state) {
return {
tasks: state.tasks
};
}
function matchDispatchToProps(dispatch){
return bindActionCreators(
{
deleteTask: deleteTaskAction,
editTask: editTaskAction
}, dispatch)
}
export default connect(mapStateToProps,matchDispatchToProps)(TaskBoard);





reducer-tasks.js



const initialState = {
tasks: [
{
id: 1,
description: "This is a task",
status: "pending"
},
{
id: 2,
description: "This is another task",
status: "pending"
},
{
id: 3,
description: "This is an easy task",
status: "pending"

}
]
}

export function Tasks (state = initialState, action) {
switch (action.type) {
case 'ADD_TASK':
return Object.assign({}, state, {
tasks: [
...state.tasks,
{
description: action.text,
status: action.status
}
]
})
break;

case 'EDIT_TASK':
return action.payload;
break;

case 'DELETE_TASK':
return Object.assign({}, state, {
status: action.status
})
break;
}

return state;
}





actionindex.js


export const addTaskAction = (task) => {
return {
type: 'ADD_TASK',
text: "Here is a sample description",
status: "pending"
}
};
export const deleteTaskAction = (task) => {
return {
type: 'DELETE_TASK',
status: "deleted"
}
};
export const editTaskAction = (task) => {
return {
type: 'EDIT_TASK',
payload: task
}
};




Answer

It's because the function 'map' can only be used for arrays, not for objects.

If you print out this.props.tasks in the render function of task-board.js you'll see that it's an OBJECT which contains the tasks array, not the actual tasks array itself.

So to fix this it's quite easy, instead of:

    return this.props.tasks.map((task) => {

it's

    return this.props.tasks.tasks.map((task) => {

Then it works

Comments