0

My State Object is a array that holds objects.PS:(Feel free to change the structure) Here is the structure:

    {
        type: ListOfTypes[Math.floor(Math.random() * ListOfTypes.length)],
        name: ListOfNames[Math.floor(Math.random() * ListOfNames.length)],
        id:  nanoid(),
        channels: [
            {
                id:  nanoid(),
                Name: ListOfChannels[Math.floor(Math.random() * ListOfChannels.length)],
                Files: [ { folder: "Folder",  documents: [ { doc: "WordDoc1.doc", isChecked: false, id:nanoid() }, { doc: "WordDoc2.doc", isChecked: false, id:nanoid() }, { doc: "WordDoc3.doc", isChecked: false, id:nanoid() }, { doc: "WordDoc4.doc", isChecked: false, id:nanoid() }] }, ],
            },
            {
                id:  nanoid(),
                Name: ListOfChannels[Math.floor(Math.random() * ListOfChannels.length)],
                Files: [{ folder: "Folder",  documents: [ { doc: "WordDoc1.doc", isChecked: false, id:nanoid() }, { doc: "WordDoc2.doc", isChecked: false, id:nanoid() }, { doc: "WordDoc3.doc", isChecked: false, id:nanoid() }, { doc: "WordDoc4.doc", isChecked: false, id:nanoid() }] }, ],
            },
            {
                id:  nanoid(),
                Name: ListOfChannels[Math.floor(Math.random() * ListOfChannels.length)],
                Files: [{ folder: "Folder", documents: [ { doc: "WordDoc1.doc", isChecked: false, id:nanoid() }, { doc: "WordDoc2.doc", isChecked: false, id:nanoid() }, { doc: "WordDoc3.doc", isChecked: false, id:nanoid() }, { doc: "WordDoc4.doc", isChecked: false, id:nanoid() }] }, ],
            }
        ]
    }

I want to change all the isChecked in every channel object, currently I'm using this function but it doesn't work as intended.

const handleChange = () => {

    const ConnectionsArray = List.map( (connection) => connection.id == connectionId ?
        {
            ...connection,
            channels: connection.channels.map( (channel) =>  channel.Name == channelName ? {
                ...channel,
                Files: channel.Files.map((file) => ({
                    ...file,
                    documents: file.documents.map((doc) => ({ ...doc, isChecked: !doc.isChecked }) )
                }))

            } : channel)
        } : connection)

    setList(ConnectionsArray)

};

3 Answers 3

2

This should do it:

function toggleChecked (connections) {
  return connections.map(connection => (connection.id === connectionId
    ? {
      ...connection,
      channels: connection.channels.map(channel => (channel.Name === channelName
        ? {
          ...channel,
          Files: channel.Files.map(file => ({
            ...file,
            documents: file.documents.map(doc => ({
              ...doc,
              isChecked: !doc.isChecked,
            })),
          })),
        }
        : channel)),
    }
    : connection));
}

Use like this:

setList(list => toggleChecked(list));

Here's another function to help with getting a random item from an array (I notice you're repeating a lot math expressions to do this in your code):

function getRandomElement (array) {
  return array[Math.floor(Math.random() * array.length)];
}

Use like this:

// before
ListOfTypes[Math.floor(Math.random() * ListOfTypes.length)]

// after
getRandomElement(ListOfTypes)
Sign up to request clarification or add additional context in comments.

2 Comments

Thanks for suggesting the helper function. The main function still gives me the same result I originally had
@Ibra You say in your question: "I want to change all the isChecked in every channel object...but it doesn't work as intended". In your example (and in mine), using channel.Name === channelName will mean that only the channel whose name matches is going to have its documents' checked values toggled. Is that "what is intended"? If not, can you clarify what you really intend to happen?
1

Probably a good time to learn how to use the "immer" library. It's perfect for situations like these where you need to make changes too deeply nested objects. Without it, making changes to objects like the one you're dealing with gets really messy and hard to deal with.

Immer is really easy to pick up and learn in a day or two. If you used it, your code could be reduced to this:

import produce from 'immer';

const handleChange = ()=>{
    const ConnectionsArray = produce(List, draft=>{
        draft.forEach((object)=>{
            object.channels.forEach((channel)=>{
                channel.Files.forEach((file)=>{
                    file.documents.forEach((document)=>{
                        document.isChecked = !document.isChecked;
                    })
                })
            })
        })
    })
}

I didn't run this code so not 100% sure it works. Either way, something like this with immer will work and be a lot easier to deal with. Notice you don't have to deal with the spread syntax or any of that, and immer will actually be creating a new object so it avoids any of the headaches associated with mutable data.

Comments

0

Check this:

const handleChange = () => {
    setList(prevState => {
        let ConnectionsArray = [...prevState];
        const itemIndex = ConnectionsArray.find(item => item.id === connectionId);
        const connection = {...ConnectionsArray[itemIndex]};
        ConnectionsArray[itemIndex] =  {
            ...connection,
            channels: connection.channels.map( (channel) =>  channel.Name == channelName ? {
                ...channel,
                Files: channel.Files.map((file) => ({
                    ...file,
                    documents: file.documents.map((doc) => ({ ...doc, isChecked: !doc.isChecked }) )
                }))

            } : channel)
        };
        return ConnectionsArray;
    })
};

3 Comments

I got this error Uncaught TypeError: ConnectionsArray.find is not a function
Sorry. I edited my answer
Uncaught TypeError: Cannot read properties of undefined (reading 'map')

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.