0

I am new to React and got a problem. I got a big a object that will contain a lot of logic for the application I am trying to build.

Based on this object I am trying to render inputfields and also update the corresponding records in the object. I got a Codesandbox with my problem setup here.

I got my 'top level' component that holds the object and passes it down to its children:

import "./styles.css";
import { useState } from "react";
import Content from "./Content";

export default function App() {
  const [formDocument, setFormDocument] = useState({
    document: {
      content: {
        sections: [
          {
            additionalFields: true,
            destroyable: false,
            key: "personalDetails",
            moveable: false,
            fields: [
              {
                fieldType: "text",
                key: "name",
                linkedFieldsKey: "name"
              },
              {
                fieldType: "text",
                key: "emailAddress",
                linkedFieldsKey: "emailAddress"
              }
            ]
          }
        ],
        records: [{ key: "1", values: ["Tim", "[email protected]"] }]
      }
    }
  });

  const updateDocument = (e) => {
    //how do I update the corresponding records for the inputfields?
    console.log("inputfield is updated");
  };

  return (
    <div className="App">
      <h1>Hello CodeSandbox</h1>
      <Content {...formDocument} updateDoc={(e) => updateDocument(e)} />
    </div>
  );
}

Now I got a child that uses the formDocument object called Content.jsx and I want to update the corresponding records in the formDocument object. This is the Content.jsx:

export default function Content({ updateDoc, ...formDocument }) {
  return (
    <div>
      <input
        style={{ display: "block", marginTop: "10px" }}
        type="text"
        value={formDocument.document.content.records[0].values[0]}
        onChange={(e) => updateDoc(e)}
      />

      <input
        style={{ display: "block", marginTop: "10px" }}
        type="text"
        value={formDocument.document.content.records[0].values[1]}
        onChange={(e) => updateDoc(e)}
      />
    </div>
  );
}

How do I update the correct records without making a function for each and every inputfield?

2 Answers 2

2

I do think that you should spit the States but the code for this goes as follows :-

import "./styles.css";
import { useState } from "react";
import Content from "./Content";

export default function App() {
  const [formDocument, setFormDocument] = useState({
    document: {
      content: {
        sections: [
          {
            additionalFields: true,
            destroyable: false,
            key: "personalDetails",
            moveable: false,
            fields: [
              {
                fieldType: "text",
                key: "name",
                linkedFieldsKey: "name"
              },
              {
                fieldType: "text",
                key: "emailAddress",
                linkedFieldsKey: "emailAddress"
              }
            ]
          }
        ],
        records: [{ key: "1", values: ["Tim", "[email protected]"] }]
      }
    }
  });

  const updateDocument = (e, index) => {
    //how do I update the corresponding records for the inputfields?
    let new_document = {...formDocument};
    new_document['document']['content']['records'][0]['values'][index]=e.target.value;
    setFormDocument(new_document);
  };

  return (
    <div className="App">
      <h1>Hello CodeSandbox</h1>
      <Content {...formDocument} updateDoc={updateDocument} />
    </div>
  );
}

The Content.js

export default function Content({ updateDoc, ...formDocument }) {
  return (
    <div>
      {formDocument.document.content.records[0].values.map((elem, i) => (
        <input
          style={{ display: "block", marginTop: "10px" }}
          type="text"
          value={elem}
          onChange={(e) =>
            updateDoc(e,i)
          }
        />
      ))}
    </div>
  );
}
Sign up to request clarification or add additional context in comments.

4 Comments

Thank you. Why do you say you recommend splitting the state? What is your reasoning behind that? Also, what is the difference between updateDoc={updateDocument} you used in your code and my original: updateDoc={(e) => updateDocument(e)}? Thanks in advance :).
No difference between updateDoc={updateDocument} and updateDoc={(e) => updateDocument(e)} but updateDoc={updateDocument} is much more cleaner.
Splitting your code makes it easier for reusability and readability. new_document['document']['content']['records'][0]['values'] seems unnecessary if you can simply boil it down to a simple array
Thank you for answer but i had an issue when using that style its about; when state is update, my view also update but cause of this input will be un-focused. Maybe I need to create a component for that row.
1

When updating an object/array in React, you have to make sure you update it with a "new" item. For doing that, you could create a copy like this:

const arrayCopy = [...array]
const objectCopy = {...object}

By updating the state using the same object or array, React won't kow that element has been updated.

So for example, if you have this in the state:

const [document, setDocument] = useState({
  users: [
    { name: 'Peter', email: '[email protected]' },
    { name: 'Michael', email: '[email protected]' },
  ]
})

Then I would follow these steps in order to update the state properly:

// Create a copy of the object in the state
let updatedObject = {...document}

// Update it as needed
let newUsers = [...document.users]
newUsers[1].name = 'Manolo'

const updatedObject = {
  ...document,
  users: [...newUsers]
}

// Update the state with a copy of the new object
// For doing so, I'd pass a function callback
setUsers(() => ({ ...updatedObject }))

That should make rerender your component and see the changes.


I would also reorganize the state a little bit. Split it when needed, you can use more than one state variable. That will help you locate the errors and debug it better. Also improves readability and will let you write better code.

1 Comment

This still mutates the user object itself. To avoid it you should spread the mutated object as well newUsers[1] = {...newUsers[1], name: 'Manolo'}

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.