Search code examples
javascriptreactjsmongoosereact-router-dom

How to get data from loader hook into an array then pass in to component


please see my code below. I am currently trying to create a gantt chart using syncfusion react gantt charts. The code works fine as is but I now want to change the data in the GanttData array which is the data source for the GanttComponent so that it is dynamic. I am using react router dom to pull in data from a database using the loader hook. Once I get this data I want to pull out some dates and put them in the GanttData array but I don't know how as I can't use useLoaderData unless it is in a function. Can anyone assist? Apologies if this isn't clear. Please let me know if you need more information.

export const loader = async ({ request, params }) => {
  try {
    const { data } = await customFetch.get(`/projects`);
    return data;
  } catch (error) {
    toast.error(error?.response?.data?.msg);
    return redirect("/dashboard/all-jobs");
  }
};

const GanttData = [
  {
    TaskID: 1,
    ProjectNo: "29895",
    TaskName: "Stoneybridge WTW",
    StartDate: new Date("04/02/2019"),
    EndDate: new Date("05/21/2019"),
    subtasks: [
      {
        TaskID: 1.1,
        TaskName: "Sodium Carbonate",
        StartDate: new Date("04/02/2019"),
        Duration: 4,
        Progress: 150,
        comments: "unlucky",
        subtasks: [
          {
            TaskID: 1.11,
            TaskName: "Design",
            StartDate: new Date("04/02/2019"),
            Duration: 30,
            Progress: 150,
          },
          {
            TaskID: 1.12,
            TaskName: "Workshop",
            StartDate: new Date("05/02/2019"),
            Duration: 30,
            Progress: 150,
          },
          {
            TaskID: 1.13,
            TaskName: "Site",
            StartDate: new Date("06/02/2019"),
            Duration: 30,
            Progress: 150,
          },
        ],
      },
      {
        TaskID: 1.2,
        TaskName: "PACl",
        StartDate: new Date("04/02/2019"),
        Duration: 4,
        Progress: 150,
        comments: "unlucky",
        subtasks: [
          {
            TaskID: 1.21,
            TaskName: "Design",
            StartDate: new Date("04/02/2019"),
            Duration: 30,
            Progress: 150,
          },
          {
            TaskID: 1.22,
            TaskName: "Workshop",
            StartDate: new Date("05/02/2019"),
            Duration: 30,
            Progress: 150,
          },
          {
            TaskID: 1.23,
            TaskName: "Site",
            StartDate: new Date("06/02/2019"),
            Duration: 30,
            Progress: 150,
          },
        ],
      },
      {
        TaskID: 1.3,
        TaskName: "Ammonium Sulphate",
        StartDate: new Date("04/02/2019"),
        Duration: 4,
        Progress: 150,
        comments: "unlucky",
        subtasks: [
          {
            TaskID: 1.31,
            TaskName: "Design",
            StartDate: new Date("04/02/2019"),
            Duration: 30,
            Progress: 150,
          },
          {
            TaskID: 1.2,
            TaskName: "Workshop",
            StartDate: new Date("05/02/2019"),
            Duration: 30,
            Progress: 150,
          },
          {
            TaskID: 1.13,
            TaskName: "Site",
            StartDate: new Date("06/02/2019"),
            Duration: 30,
            Progress: 150,
          },
        ],
      },
    ],
  },
  {
    TaskID: 2,
    ProjectNo: "31139",
    TaskName: "Barra WTW",
    StartDate: new Date("04/02/2019"),
    EndDate: new Date("05/21/2019"),
    subtasks: [
      {
        TaskID: 2.1,
        TaskName: "Sodium Carbonate",
        StartDate: new Date("04/02/2019"),
        Duration: 4,
        Progress: 150,
        comments: "unlucky",
        subtasks: [
          {
            TaskID: 2.11,
            TaskName: "Design",
            StartDate: new Date("04/02/2019"),
            Duration: 30,
            Progress: 150,
          },
          {
            TaskID: 2.12,
            TaskName: "Workshop",
            StartDate: new Date("05/02/2019"),
            Duration: 30,
            Progress: 150,
          },
          {
            TaskID: 2.13,
            TaskName: "Site",
            StartDate: new Date("06/02/2019"),
            Duration: 30,
            Progress: 150,
          },
        ],
      },
      {
        TaskID: 2.2,
        TaskName: "Ammonium Sulphate",
        StartDate: new Date("04/02/2019"),
        Duration: 4,
        Progress: 150,
        comments: "unlucky",
        subtasks: [
          {
            TaskID: 2.21,
            TaskName: "Design",
            StartDate: new Date("04/02/2019"),
            Duration: 30,
            Progress: 150,
          },
          {
            TaskID: 2.22,
            TaskName: "Workshop",
            StartDate: new Date("05/02/2019"),
            Duration: 30,
            Progress: 150,
          },
          {
            TaskID: 2.23,
            TaskName: "Site",
            StartDate: new Date("06/02/2019"),
            Duration: 30,
            Progress: 150,
          },
        ],
      },
    ],
  },
];

const splitterSettings = {
  position: "30%",
};

const timelineSettings = {
  timelineUnitSize: 60,
  timelineViewMode: "Month",
  topTier: {
    unit: "Year",
  },
  bottomTier: {
    unit: "Month",
  },
};

function GanttChart() {
  const { projects } = useLoaderData();

  console.log(projects);
  console.log(projects[0].projectEnd);
  const taskFields = {
    id: "TaskID",
    name: "TaskName",
    startDate: "StartDate",
    duration: "Duration",
    progress: "Progress",
    child: "subtasks",
  };
  return (
    <GanttComponent
      dataSource={GanttData}
      taskFields={taskFields}
      height="530px"
      width="1200px"
      splitterSettings={splitterSettings}
      allowResizing={false}
      timelineSettings={timelineSettings}
      collapseAllParentTasks={true}
    >
      <ColumnsDirective maxWidth="100" minWidth="70" width="10">
        <ColumnDirective
          field="TaskID"
          width="100"
          maxWidth="100"
          minWidth="100"
        ></ColumnDirective>
        <ColumnDirective
          field="ProjectNo"
          headerText="Project Number"
          width="80"
          allowResizing={false}
          maxWidth="100"
          minWidth="100"
        ></ColumnDirective>
        <ColumnDirective
          field="TaskName"
          headerText="Task Name"
          width="200"
          maxWidth="100"
          minWidth="100"
        ></ColumnDirective>
      </ColumnsDirective>
      <Inject services={[Resize]} />
    </GanttComponent>
  );
}

export default GanttChart;

Solution

  • The problem you have is that GanttData is a standard JS variable so that each time your component (a JS function) gets rendered (i.e. "run the function"), then the variable GanttData is recreated and re-initialized with the hard coded values you have provided it.

    If you want to have a variable that holds data, be able to update that data and see that changed data across renders, then you want to use a state variable (useState()) or a reference variable (useRef()). The benefit of a state variable is that when you update the value with the "set state function" then the component that has that state variable (the component that calls useState()) will cause the component to be re-rendered. The benefit of reference variables is that you can update their value while not causing the component to re-render.

    So in your case I suspect you want to define GanttData (which I would recommend to rename as ganttData) as a state variable (const [ganttData, setGanttData] = useState([{ ...... }])) and then in your loader() function update the state variable using setGanttData() to put the newly fetched values into ganttData, which will then cause the component to re-render showing you the newly obtained values.