Home > Enterprise >  Pulling JSON String From C# Controller Into React Page With Axios
Pulling JSON String From C# Controller Into React Page With Axios

Time:01-11

I'm trying to craft a JSON string made out of a list of 4 objects and send it from my C# controller over to my React function with Axios and put the data in for the class names of my divs to change their styling based on whether they are active or not. With my code, I am getting a UncaughtTypeError: Cannot read properties of null (reading '0'). I think the data is not getting to the function but I'm not sure why. Code below:

ServerStatuses.js (where I'm trying to set the value of the classNames)

import React, { useState, useEffect } from 'react';
import axios from "axios";

function ServerStatuses() {
    const [serverCycleData, setServerCycleData] = useState(null);

    useEffect(() => {
        //sets the interval for the serverCycle data to be sent over every 2 seconds
        const serverCycleData = () => {
            axios.get("/serverCycle")
                .then(res => {
                    setServerCycleData(res.data);
                })
        }
        serverCycleData();
        const interval = setInterval(() => {
            serverCycleData()
        }, 50000);
        return () => clearInterval(interval);
    }, []);

        return (
            <div id="statuses">
                <div id="LWStatus" className={serverCycleData[0].className}>SERVER</div>
                <div id="CONAStatus" class={serverCycleData[1].className}>CONA</div>
                <div id="PDAStatus" class={serverCycleData[2].className}>PDA</div>
                <div id="OverallStatus" class={serverCycleData[3].className}>ERROR</div>
            </div>
        )
    };

export default ServerStatuses;

ProductionController.cs (first is the API call I have)


        [HttpGet]
        [Route("/hGrabLocation")]
        public string GrabLocation()
        {
            var plantLocation = "LOCATION HERE";
            //using the object here to pull the data
            if (ObjSiteConfiguration.Initialized)
            {
                plantLocation = ObjSiteConfiguration.Palletizers[0].PlantName;
            }
            else
            {
                plantLocation = "Site not initialized";
            }

            return plantLocation;

        }

ProductionController.cs (this is just the list that I created at the start for the values to be stored and pulled from in)

private List<ObjServerStatus> serverStatuses = new()
        {
                new ObjServerStatus{serverType = "LW", serverStatus = false, statusClass = "header-icon_error"},
                new ObjServerStatus{serverType = "CONA", serverStatus = false, statusClass = "header-icon_error"},
                new ObjServerStatus{serverType = "PDA", serverStatus = false, statusClass = "header-icon_error"},
                new ObjServerStatus{serverType = "OVERALL", serverStatus = false, statusClass = "header-icon_error"}
            };

I tried to run the site and keep getting a Uncaught TypeError: Cannot read properties of null (reading '0'). I was expecting to have my header load and the div tags would load with the correct class attached.

CodePudding user response:

serverCycleData is null initially, before the response loads

Either add an early return statement

function ServerStatuses() {
  const [serverCycleData, setServerCycleData] = useState(null);

  useEffect(() => {
    //sets the interval for the serverCycle data to be sent over every 2 seconds
    const serverCycleData = () => {
      axios.get("/serverCycle").then((res) => {
        setServerCycleData(res.data);
      });
    };
    serverCycleData();
    const interval = setInterval(() => {
      serverCycleData();
    }, 50000);
    return () => clearInterval(interval);
  }, []);

  if (!serverCycleData) return null

  return (
    <div id="statuses">
      <div id="LWStatus" className={serverCycleData[0].className}>
        SERVER
      </div>
      <div id="CONAStatus" class={serverCycleData[1].className}>
        CONA
      </div>
      <div id="PDAStatus" class={serverCycleData[2].className}>
        PDA
      </div>
      <div id="OverallStatus" class={serverCycleData[3].className}>
        ERROR
      </div>
    </div>
  );
}

Or use optional chaining

function ServerStatuses() {
  const [serverCycleData, setServerCycleData] = useState(null);

  useEffect(() => {
    //sets the interval for the serverCycle data to be sent over every 2 seconds
    const serverCycleData = () => {
      axios.get("/serverCycle").then((res) => {
        setServerCycleData(res.data);
      });
    };
    serverCycleData();
    const interval = setInterval(() => {
      serverCycleData();
    }, 50000);
    return () => clearInterval(interval);
  }, []);

  return (
    <div id="statuses">
      <div id="LWStatus" className={serverCycleData?.[0].className}>
        SERVER
      </div>
      <div id="CONAStatus" class={serverCycleData?.[1].className}>
        CONA
      </div>
      <div id="PDAStatus" class={serverCycleData?.[2].className}>
        PDA
      </div>
      <div id="OverallStatus" class={serverCycleData?.[3].className}>
        ERROR
      </div>
    </div>
  );
}

CodePudding user response:

React runs through ServerStatus block every time it "determines it needs to". One of those times will be the first pass through before your useEffect has run.

At that point

const [serverCycleData, setServerCycleData] = useState(null);

means that the the variable in the useEffect of serverCycleData will be null.

One option would be to initialize with an array that you can deference (i.e. have your array of states expected from the server set to something meaningful, like "waiting for server").

This could look like:

const [serverCycleData, setServerCycleData] = useState(["header-icon_waiting_for_server","header-icon_waiting_for_server", "header-icon_waiting_for_server", "header-icon_waiting_for_server" ]);
  • Related