0

So inside my reducer, I have an array of objects called 'todos', and an object of 'todos' has a state which is also an array of objects, called 'comments'. And inside each of 'comments' array, I would like to define a string state 'commentText', but I can't seem to figure out how to do so. Any help would be greatly appreciated.

Following is an example of what I would like to achieve:

let todoReducer = function(todos = [], action){
    switch(action.type){
        case 'ADD_TODO':
            return [{
                comments:[{
                    commentText: action.commentText
                }]
            }, ...todos]

        case 'CREATE_COMMENT_ARRAY':
            return [{
                commentText: action.eventValue
            ], ...todos.comments] //Referencing todos.comments as 'comments' array of objects of an object of 'todos' array. Would like to directly update if possible and build up 'comments' array.

       default:
        return todos
    }
}
export default todoReducer

NEW EDIT**:

case 'UPDATE_COMMENT':
  return todos.map(function(todo){
    if(todo.id === action.id){
      //want to add a new a 'comment' object to the todo's 'comments' array
    //Something like the following:
        todo.comments: [{
            commentText: action.commentText
        }, ...todo.comments]
    }
  })
5
  • Updeep makes it easy to perform updates of nested objects and arrays; I'd recommend taking a look at it. Commented Jun 23, 2016 at 22:27
  • stackoverflow.com/questions/37980109/… duplicate Commented Jun 23, 2016 at 23:01
  • @xiaofan2406 I checked it out but I can't seem to grasp the concept well enough. If you don't could you provide an example according to what I provided? Thank you Commented Jun 23, 2016 at 23:04
  • Are you trying to update the commentText of a particular Todo? If so, you'll probably need to give the Todos unique IDs so you can filter through the list of them to find the one you need to update. Otherwise there's no way to tell one Todo from another. Commented Jun 24, 2016 at 0:33
  • @dannyid Yes that's exactly it! If you don't mind, could you show an example? I can't seem to get it to work... Commented Jun 24, 2016 at 2:28

1 Answer 1

0

This sounds like a great use case for the .map() Array method.

Assuming your data looks like this:

var todos = [
  {
    id: 1,
    title: 'Todo 1 Title',
    body: 'Todo 1 Body',
    date: 1425364758,
    comments: [
      {
        id: 1,
        commentorId: 42069,
        text: 'Todo 1, Comment 1 Text',
        date: 1425364758
      },
      {
        id: 2,
        commentorId: 42069,
        text: 'Todo 1, Comment 2 Text',
        date: 1425364758
      },
      {
        id: 3,
        commentorId: 42069,
        text: 'Todo 1, Comment 3 Text',
        date: 1425364758
      }
    ]
  },
  {
    id: 2,
    title: 'Todo 2 Title',
    body: 'Todo 2 Body',
    date: 1425364758,
    comments: [
      {
        id: 1,
        commentorId: 42069,
        text: 'Todo 2, Comment 1 Text',
        date: 1425364758
      }
    ]
  },
  {
    id: 3,
    title: 'Todo 3 Title',
    body: 'Todo 3 Body',
    date: 1425364758,
    comments: [
      {
        id: 1,
        commentorId: 42069,
        text: 'Todo 3, Comment 1 Text',
        date: 1425364758
      },
      {
        id: 2,
        commentorId: 42069,
        text: 'Todo 3, Comment 2 Text',
        date: 1425364758
      }
    ]
  }
];

When updating a comment, you'd need to pass in a todoId and a commentId so you know what to look for. When adding a comment, you'd only need to pass in a todoId so you know which todo to update:

const todoReducer = (todos = [], action) => {
  switch(action.type) {
    case 'ADD_TODO':
      return [
        action.todo,
        ...todos
      ];
    case 'ADD_COMMENT':
      const { todoId, comment } = action;

      // Map through all the todos. Returns a new array of todos, including the todo with a new comment
      return todos.map(todo => {
        // Look for the todo to add a comment to
        if (todo.id === todoId) {
          // When the todo to update is found, add a new comment to its `comments` array
          todo.comments.push(comment);
        }
        // Return the todo whether it's been updated or not
        return todo;
      });
    case 'UPDATE_COMMENT':
      const { todoId, commentId, commentText } = action;

      // Map through all the todos. Returns a new array of todos, including the todo with the updated comment
      return todos.map(todo => {
        // First find the todo you want
        if (todo.id === todoId) {
          // Then iterate through its comments
          todo.comments.forEach(comment => {
            // Find the comment you want to update
            if (comment.id === commentId) {
              // and update it
              comment.text = commentText;
            }
          });
        }
        // Return the todo whether it's been updated or not
        return todo;
      });
    default:
      return todos;
  }
};
export default todoReducer;

As for your payloads, you can make them whatever you want, and they'll be created in your action creator. For example, here's an implementation of ADD_TODO that gives the todo a unique ID, timestamps it, and adds an empty comments array before firing the action:

import uuid from 'node-uuid';
const addTodo = ({title, body}) => {
  const id = uuid.v4();
  const date = new Date().getTime();
  return {
    type: 'ADD_TODO',
    todo: {
      id,
      title,
      body,
      date,
      comments: []
    }
  };
};

Your ADD_COMMENT action creator might look something like this:

import uuid from 'node-uuid';
const addComment = ({todoId, commentorId, commentText}) => {
  const id = uuid.v4();
  const date = new Date().getTime();
  return {
    type: 'ADD_COMMENT',
    todoId,
    comment: {
      id,
      commentorId,
      date,
      text: commentText
    }
  };
};

This is untested but hopefully gives you an idea.

Sign up to request clarification or add additional context in comments.

5 Comments

Thanks for the guide! Trying to still wrap my head around it. Just to clarify, how would the payloads be defined in action creators?
Also, I would like to just create a 'comments' empty array in 'ADD_TODO' and not set values inside, and when UPDATE_COMMENT is activated, be able to continue to add a new comment to the initialized empty 'comments' array.
I updated the original post with code, under NEW EDIT.
Just checking to see if you were able to view the new comment.
Hey @JoKo, check out my updated answer. I expounded a bunch.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.