0

I have two files/components:

  • Createrisk.jsx for creating individual risks
  • Tablepage.jsx displays the risks in an MUI Data Grid

The problem is Tablepage renders only the attributes from Createrisk which are not dependent on user input i.e the ID and a Test attribute. I believe this makes sense, on first render attributes tied to inputs are empty.

How do I get the Tablepage component to re-render? Ideally tied to this event on Createrisk:

<button onClick={handleSubmission}>Store my data</button>

I have a vague idea I need a useState, but I am unsure how to do this across different components (JSX files).

Createrisk.jsx:

function Createrisk() {
  function handleSubmission() {
    var risks = JSON.parse(localStorage.getItem("allrisks"));
    if (risks == null) {
      risks = [];
    }
    let riskitem = {
      riskname: document.getElementById("rname").value,
      riskdesc: document.getElementById("rdesc").value,
      riskimpact: document.getElementById("rimpact").value,
      test: "test",
    };
    risks.push(riskitem);
    let i = 1;
    risks.map((n) => {
      n["id"] = i;
      i++;
    });

    localStorage.setItem("allrisks", JSON.stringify(risks));
  }

  return (
    <div>
      <input type="text" id="rname" placeholder="Risk Name" />
      <input type="text" id="rdesc" placeholder="Risk Description" />
      <input type="text" id="rimpact" placeholder="Risk Impact" />
      <button onClick={handleSubmission}>Store my data</button>
    </div>
  );
}
export default Createrisk;

Tablepage.jsx:

function Tablepage() {
  const risksfromstorage = JSON.parse(localStorage.getItem("allrisks"));

  const columns = [
    { field: "id", headerName: "ID", width: 350 },
    { field: "rname", headerName: "Risk Name", width: 350 },
    { field: "rdesc", headerName: "Risk Desc", width: 350 },
    { field: "rimpact", headerName: "Risk Impact", width: 350 },
    { field: "test", headerName: "test", width: 350 },
  ];

  const rows = risksfromstorage.map((row) => ({
    id: row.id,
    rname: row.rname,
    rdesc: row.rdesc,
    rimpact: row.rimpact,
    test: row.test,
  }));

  return (
    <div>
      <DataGrid getRowId={(row) => row.id} columns={columns} rows={rows} />
    </div>
  );
}

export default Tablepage;

As one can see, the Array/Object gets added to localstorage. Only the non-input attributes are populated in the table (ID & Test)

Img showing Table and LocalStorage

0

1 Answer 1

0

It appears that the "allrisks" data value stored in localStorage is your source of truth. Instead of attempting to work with localStorage directly, create a state in a common ancestor component that is initialized from localStorage and pass the state down as props to these two components. When the state is updated this will trigger a React component re-render.

Example:

const CommonAncestor = () => {
  // Lazy initialize state from localStorage
  const [allRisks, setAllRisks] = React.useState(() => {
    return JSON.parse(localStorage.getItem("allrisks")) || [];
  });

  // Side-effect to persist state to localStorage
  React.useEffect(() => {
    localStorage.setItem("allrisks", JSON.stringify(allRisks));
  }, [allRisks]);

  // Handler to update state
  const addRisk = (risk) => {
    setAllRisks(allRisks => allRisks.concat(risk));
  };

  return (
    <>
      ...
      <CreateRisk addRisk={addRisk} />
      ...
      <TablePage rows={allRisks} />
      ...
    </>
  );
};

CreateRisk.jsx

import { nanoid } from 'nanoid';

function CreateRisk({ addRisk }) {
  function handleSubmission() {
    addRisk({
      id: nanoid(),
      riskname: document.getElementById("rname").value,
      riskdesc: document.getElementById("rdesc").value,
      riskimpact: document.getElementById("rimpact").value,
      test: "test",
    });
  }

  return (
    <div>
      <input type="text" id="rname" placeholder="Risk Name" />
      <input type="text" id="rdesc" placeholder="Risk Description" />
      <input type="text" id="rimpact" placeholder="Risk Impact" />
      <button onClick={handleSubmission}>Store my data</button>
    </div>
  );
}

TablePage.jsx

const columns = [
  { field: "id", headerName: "ID", width: 350 },
  { field: "rname", headerName: "Risk Name", width: 350 },
  { field: "rdesc", headerName: "Risk Desc", width: 350 },
  { field: "rimpact", headerName: "Risk Impact", width: 350 },
  { field: "test", headerName: "test", width: 350 },
];

function TablePage({ rows }) {
  return (
    <div>
      <DataGrid
        getRowId={(row) => row.id}
        columns={columns}
        rows={rows}
      />
    </div>
  );
}
Sign up to request clarification or add additional context in comments.

8 Comments

thanks a lot for your suggestion, I will read up and test this!
I unfortunately get "Uncaught TypeError: addRisk is not a function at handleSubmission (Createrisk.jsx:9:5)" when I try and add a risk: function CreateRisk({ addRisk }) { function handleSubmission() { addRisk({
@user29980937 Did you declare an addRisk callback function in the parent/ancestor component to be passed down as a prop? Did you pass any addRisk={addRisk} to the CreateRisk component? Here's a running sandbox demo.
Thanks Drew for your reply! Regarding these two questions, I have no idea to be honest... Is it something different from the code you gave? I have 3 files now: CommonAncestor.JSX CreateRisk.JSX TablePage.JSX^ They each have the corresponding code from above. I have exported/imported them between each other. I exported each file with "Export Default Function name". I also wrapped the "const CommonAncestor......" code in its own function so I can export. So I guess that my initial problem still remains i.e how do I share this info across different components /JSX files.
@user29980937 No, the code in my answer and what I implemented in my sandbox were basically the minimum necessary to lift the state and handlers up the React tree to be sharable across sibling components. Sharing state between components may be helpful in explaining in more detail what I've suggested here. You said in a now-deleted comment that you had forked my sandbox. Is there an issue there in that code? If you can re-create the issue in a running sandbox I can take a look.
|

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.