0

I'm trying to make an obligatory Todo app to help with my React learning . The behavior I'm going for is multiple Todo lists, where you select a todo name and the list of todo items for that show. Select a different name list and it's list todo items show, etc (like wunderlist/msft todo). It's using static json where each item has a child array.

I'm realizing I have no idea how to update the text in the nested array and I can't seem to find any relevant examples of this. Will someone show me how this is done or point me in the right direction?

In my POC on codesandbox each todo has a button where all I'd like to do (for now) is change the text to 'changed' when clicking on the button. Basically I'd like to do this:

todoData[selectedIndex].TodoList[index].Title = 'Changed; 

But the es6/react way using the spread operator

Here's a POC : https://codesandbox.io/s/zealous-lovelace-xtexr?file=/src/App.js

My data looks like this:

const TodoData = [
    {
        "Id": 1,
        "Title": "Groceries",
        "TodoList": [
            {
                "Id": 1,
                "Title": "Apples",
                "IsChecked": false
            },
            {
                "Id": 2,
                "Title": "Oranges",
                "IsChecked": false
            },
            {
                "Id": 3,
                "Title": "Bananas",
                "IsChecked": true
            }
        ]
    },
    {
        "Id": 2,
        "Title": "Daily Tasks",
        "TodoList": [{
            "Id": 11,
            "Title": "Clean Kitchen",
            "IsChecked": false
        },
        {
            "Id": 12,
            "Title": "Feed Pets",
            "IsChecked": false
        },
        {
            "Id": 13,
            "Title": "Do Stuff",
            "IsChecked": false
        }]
    },
    {
        "Id": 3,
        "Title": "Hardware Store",
        "TodoList": []
    },
    {
        "Id": 4,
        "Title": "Costco",
        "TodoList": [{
            "Id": 21,
            "Title": "Diapers",
            "IsChecked": false
        },
        {
            "Id": 22,
            "Title": "Cat Food",
            "IsChecked": false
        },
        {
            "Id": 23,
            "Title": "Apples",
            "IsChecked": false
        },
        {
            "Id": 24,
            "Title": "Bananas",
            "IsChecked": false
        }]
    },
    {
        "Id": 5,
        "Title": "Work",
        "TodoList": [
            {
                "Id": 34,
                "Title": "TPS Reports",
                "IsChecked": true
            }
        ]
    }
]

export default TodoData;

And the code:

function App() {

  const [todoData, setTodoData] = useState([]);
  const [selectedIndex, setSelectedIndex] = useState(0);

  useEffect(() => {
    setTodoData(TodoData);
  }, []);

  const addSelectedIndex = (index) => {
    setSelectedIndex(index);
  }

  const handleInputChange = (todoItem, todoItemIndex) => {
    const target = todoItem;
    const value = target.type === 'checkbox' ? target.checked : target.value;
  };

  const handleTextChange = (item, index) => {
    const updatedTitle = 'Changed';
    //Not sure what to do here
  }

  return (
    <div className="App">
      <ul className="pointer">
        {todoData.map((todo, todoIndex) => (
          <li key={todo.Id} onClick={() => addSelectedIndex(todoIndex)}>
            {todo.Title + ' (' + todo.TodoList.length + ')'}
          </li>
        ))}
      </ul>
      <ul>
        {todoData[selectedIndex] && todoData[selectedIndex].TodoList.map((todoItem, todoItemIndex) => (
          <li key={todoItem.Id}>
            <input type="checkbox" id="gridCheck" checked={todoItem.IsChecked} onChange={() => { handleInputChange(todoItem, todoItemIndex) }} />
            <label htmlFor="gridCheck">
              {todoItem.Title}
            </label>
            <button onClick={() => handleTextChange(todoItem, todoItemIndex)}>Change</button>
          </li>

        ))}
      </ul>
    </div>
  );
}

2 Answers 2

1

Here is a working example: https://codesandbox.io/s/modest-dewdney-cnuk7?file=/src/App.js

Essentially you want to use the map method on the list (map method does not mutate the original list).

First use selectedIndex to determine if the current looping list object is the one we are looking for, if it is not, we return it immediately (not making any changes).

If it is, we first clone the list object using spread operator, update the todos in that list using the same concept.

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

Comments

1

I've updated your sandbox. You are correct - you don't need mutate state object. You should return new updated object.

But we have a good news. In your case, would be reasonable to use immer. It's allow to reduce code. Here an example.

Comments

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.