skip to Main Content

I am new to ReactJs .I’m trying to use the useState hook in react function base component but the value of the state is not getting updated when I am calling the function. When receiving data via websocket, it is not possible to update the data on the line graph using the construct useState and useEffect.

client receives data via websocket:

const myWs = new WebSocket('ws://localhost:8000');
// обработчик проинформирует в консоль когда соединение установится
myWs.onopen = function () {
    console.log('подключился');
};

// обработчик сообщений от сервера
myWs.onmessage = function (message) {
    const jsonParse = JSON.parse(message.data);      
    try {   
      
      let temp = {x:setInterval((counter) =>{
        if(mockLineData[0].data.length >= 50){
          mockLineData[0].data.shift();
          counter++
        }
        else{
          counter++
        }
      }, 3000), y:jsonParse[0]['value_state']};
      mockLineData[0].data.push(temp);
      console.log(mockLineData[0].data);

    } catch (error) {
        console.log('Error: ', error);
    }
};




export const mockLineData = [
  {
    id: "ИБП Uвх",
    color: tokens("dark").redAccent[200],
    data: [
      {
        x: 0,
        y: 0
      },
      
    ],
  },
];

Next I’m trying to update data in a table using the construct useState and useEffect

import { mockLineData as data } from "../data/dataLineGraph";

const LineChart = ({ isCustomLineColors = false, isDashboard = false }) => {
  const theme = useTheme();
  const colors = tokens(theme.palette.mode);
  const [state, setState] = useState();
  
  useEffect(() => {
    setInterval(()=>{
      setState(data);
    },1000)
  }, []);


  return (
    <ResponsiveLine
      data={state}
      theme={{
        axis: {
          domain: {
            line: {
              stroke: colors.grey[100],
            },
          },
          legend: {
            text: {
              fill: colors.grey[100],
            },
          },
          ticks: {
            line: {
              stroke: colors.grey[100],
              strokeWidth: 1,
            },
            text: {
              fill: colors.grey[100],
            },
          },
        },
        legends: {
          text: {
            fill: colors.grey[100],
          },
        },
        tooltip: {
          container: {
            color: colors.primary[500],
          },
        },
      }}
      colors={isDashboard ? { datum: "color" } : { scheme: "nivo" }} // added
      margin={{ top: 50, right: 110, bottom: 50, left: 60 }}
      enableGridX={false}
      enableGridY={false}
      pointSize={8}
      pointColor={{ theme: "background" }}
      pointBorderWidth={2}
      pointBorderColor={{ from: "serieColor" }}
      pointLabelYOffset={-12}
      useMesh={true}
      legends={[
        {
          anchor: "bottom-right",
          direction: "column",
          justify: false,
          translateX: 100,
          translateY: 0,
          itemsSpacing: 0,
          itemDirection: "left-to-right",
          itemWidth: 80,
          itemHeight: 20,
          itemOpacity: 0.75,
          symbolSize: 12,
          symbolShape: "circle",
          symbolBorderColor: "rgba(0, 0, 0, .5)",
          effects: [
            {
              on: "hover", //hover
              style: {
                itemBackground: "rgba(0, 0, 0, .03)",
                itemOpacity: 1,
              },
            },
          ],
        },
      ]}
    />
  );
};

export default LineChart;

but the data is not updated

3

Answers


  1. Your useEffect closes over data once (empty dependency array) – hence data will always be the same object, and nothing ever gets changed even if you repeatedly call setInterval.

    Login or Signup to reply.
  2. once you didn’t send data to LineChart.
    if you get it from Parent Component – add it to props:

    const LineChart = ({ isCustomLineColors = false, isDashboard = false, data }) => {
          const theme = useTheme();
          const colors = tokens(theme.palette.mode);
          const [state, setState] = useState();
        
        .....
    
    }
    

    second – if your data changed due to lifecycle, your useEffect need to include data in dependencies array.

    so on every change in data will notify by useEffect.

    change your useEffect to:

    useEffect(() => {
       setState(data);
    }, [data]);
    

    finally your code will be seemed:

    const LineChart = ({ isCustomLineColors = false, isDashboard = false, data }) => {
       const theme = useTheme();
       const colors = tokens(theme.palette.mode);
       const [state, setState] = useState();
    
       useEffect(() => {
         setState(data);
       }, [data]);
        
        .....
    }
    
    
    Login or Signup to reply.
  3. Why does my code not work?

    At first you set the variable data just in your useEffect hook, but where did your component get this variable? You don’t initialize this variable in your LineChart component or declare this dependency as a LineChart prop so that the component get the data from it’s parent.

    Lets start with the question should your LineChart component be a Smart or Dumb react component (here is a good article if your not familier with this terms https://medium.com/@thejasonfile/dumb-components-and-smart-components-e7b33a698d43)

    I would say your LineChart component is a Dumb component, which just displays your data and has no business logic to get the data directly from the websocket.
    Because of this we will introduce your data as a LineChart prop without using any useState or useEffect hooks. Maybe you are thinking now, how should the component update when we don’t use a state combined with useEffect. Thats quite simple – Your component rerenders automatically when a prop changes as well.

    So lets solve your problem by modifying LineChart:

    const LineChart = ({ data, isCustomLineColors = false, isDashboard = false }) => {
       const theme = useTheme();
       const colors = tokens(theme.palette.mode);
       // removed useState and useEffect hook
       return (.....)
    }
    

    With this component you just have to pass your new data as prop to your LineChart and your component will be updated.

    My recommendation: Don’t mix props with the component state as long your component just uses the prop for reading/display information.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search