简体   繁体   中英

Why chart renders after second click - react-chartjs-2

I created a chart in React app with react-chartjs-2. I have 2 items on the homepage: "chart1" and "chart2". When I click on the "chart1" - chart displays with no data. After second click, data are rendering correctly. Next I want to render "chart2", but after click on that item, "chart1" renders. After second click, data for "chart2" are rendering correctly. Do you know what is the problem? I want to render every chart after first click.

Chart.js

import React, { useEffect, useState } from 'react';
import { connect } from 'react-redux';
import { Line } from 'react-chartjs-2';

import { getChartData } from '../../actions/sensors';

const Chart = (props) => {

  const [chartDataState, setChartDataState] = useState({});

  const createChart = () => {
    const id = props.match.params.id;
    props.getChartData(id);

    setChartDataState({
      labels: props.chartData.map(data => {
        const date = new Date(data.delivery_time).toLocaleDateString();
        const time = new Date(data.delivery_time).toLocaleTimeString();
        return `${time} | ${date}`;
      }),
      datasets: [
        {
          data: props.chartData.map(data => data.sensor_data),
          fill: false,
          backgroundColor: '#987316',
          borderColor: 'rgba(152, 115, 22, 0.2)',
        },
      ],
    })
  }

  useEffect(() => {
    createChart();
  }, [])

  return (  
    <div className="container">
      <div className="head" style={{'marginBottom': '30px'}}>
        <h2>Chart</h2>
        <div className="line" style={{"width": "900px"}}></div>
      </div>
      <div className="chart">
        <Line
          data={chartDataState}
          options={{
            maintainAspectRatio: false,
            legend: {
              display: false,
            }
          }}
          height={400}
        />
      </div>
    </div>
  );
}

const mapStateToProps = state => ({
  chartData: state.sensors.chartData,
})
 
export default connect(mapStateToProps, { getChartData })(Chart);

sensors (Redux action)

export const getChartData = id => (dispatch, getState) => {

  const token = getState().auth.token;

  const config = {
    headers: {
      'Content-Type': 'application/json',
      'Authorization': `Token ${token}`
    }
  } 

  axios.get(`${baseURL}/sensors_data/list/${id}`, config)
  .then(res => {
    dispatch({
      type: GET_CHART_DATA,
      payload: res.data
    })
  })
  .catch(err => console.log(err))
}

sensors (Redux reducer)

import { GET_CHART_DATA } from '../actions/types';

const initialState = {
  chartData: [],
}

export default function(state = initialState, action) {
  switch(action.type) {
    case GET_CHART_DATA:
      return {
        ...state,
        chartData: action.payload
      }
    default:
      return state;
  }

When you first click, you trigger a request for the data, but your component does not wait for that data before rendering.

I would recommend adding a condition to your return. This is how I would have done it without Redux (I've never used Redux)

return (  
  <div className="container">
    <div className="head" style={{'marginBottom': '30px'}}>
      <h2>Chart</h2>
      <div className="line" style={{"width": "900px"}}></div>
    </div>
    <div className="chart">
      {chartDataState.length > 0 ? 
      <Line
        data={chartDataState}
        options={{
          maintainAspectRatio: false,
          legend: {
            display: false,
          }
        }}
        height={400}
      />
      : <div>Loading...</div>}
    </div>
  </div>
);

Basically: you don't want your component to render the chart before the data is returned.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM