Search code examples
recoiljs

Updating the value of an array of objects stored in Recoil js


Currently I am storing a list of post in my recoil state and I would like to be able to update the title of a post by its id and see the change in realtime.

On the docs I saw an example on how to remove an object from the array and that worked fine but what If I wanted to update the value of an object in the array?

This is what I've been looking at on the docs, but this example just iterates a number. https://recoiljs.org/docs/api-reference/core/useRecoilState

The structure of my state that is storing the posts is as follows:

[
 {
  id: 1
  title: "test 1"
  desc: ""
 },
{
  id: 2
  title: "test 2"
  desc: ""
 },
{
  id: 3
  title: "test 3"
  desc: ""
 }
]

This is my current attempt but i am getting the error: "Cannot read properties of undefined (reading 'map')"

setArticles(prevState => ({
            todoItems: prevState.todoItems.map(
              post => post.id === id ? { ...post, title: 'New Title' }: post
            )
          }))

...Any help on how I would write my set state would be much appreciated!


Solution

  • Use the following code :

    import React from 'react';
    import { useRecoilState, atom, RecoilRoot } from 'recoil';
    
    const listState = atom({
      key: 'listState',
      default: [
        {
          id: 1,
          title: 'test 1',
          desc: '',
        },
        {
          id: 2,
          title: 'test 2',
          desc: '',
        },
        {
          id: 3,
          title: 'test 3',
          desc: '',
        },
      ],
    });
    
    export default function App() {
      return (
        <RecoilRoot>
          <TextInput />
        </RecoilRoot>
      );
    }
    
    function TextInput() {
      let [list, setList] = useRecoilState(listState);
    
      const onChange = (event, id) => {
        let newList = [...list].map((item) => {
          if (item.id === id) return { ...item, title: event.target.value };
          else return item;
        });
    
        setList(newList);
      };
    
      return list.map((item) => (
        <div key={item.id}>
          <input
            type="text"
            value={item.title}
            onChange={(e) => onChange(e, item.id)}
          />
          <br />
          Echo: {item.title}
        </div>
      ));
    }