React Chart Js Class Component

850 views Asked by At

I converted my code to a class component and things started to break. I figured out where it's breaking but I can't seem to figure out why its breaking. Think you guys can help me out?

What happens is when I change the name in this input field (red arrow section) componentDidMount fires off and gives me this error.

So I've narrowed down the issue to when I setState and do data: chartData in componentDidMount. If that bit of code is commented out, it works otherwise it doesn't.

Chartjs can take an empty object hence why I'm doing the check to only update the value if there is something to update it with. But yeah, I really don't know what's wrong or how to fix it...

All my code was working before I made it into a class component, I would change it back but that input field at the top, I was having trouble dynamically updating it before. I will show my before and after code too. BTW I did remove some functions as to not make the code so lengthy and I can verify those functions were not breaking my code

Chart View enter image description here

enter image description here

Before Change

import React, {useEffect, useState} from 'react'
import {Redirect} from "react-router-dom";
import {connect} from 'react-redux'
import {Line} from "react-chartjs-2";
import moment from "moment";
import "./DeviceDetails.css"
import axios from "axios";

const DeviceDetails = (props) => {
    const {auth, device, sensorData,deviceName} = props
    const [chartData, setChartData] = useState({})
    const today = moment().format().split("T")[0]
    const localTime = moment(device.dateTime).format("DD/MM/YYYY HH:mm").toString()

    
    useEffect(() => {
        let chartData = {}

        if (sensorData) {
            chartData = sensorData.map(data => {
                const container = {};
                container.x = moment(data.dateTime)
                container.y = data.soilMoisturePercent
                return container
            })
        }


        const chart = () => {
            setChartData({
                labels: [moment().startOf('day'), moment().endOf('day')],
                datasets: [
                    {
                        label: "Moisture Levels",
                        data: chartData,
                        backgroundColor: ['rgba(75,192,192,0.6)'],
                        borderWidth: 4
                    }
                ],
            })
        }

        chart()
    }, [sensorData]);

    const options = {...}

    if (!auth.uid) {
        return <Redirect to="/signin"/>
    } else {
        return (
            <div className="fitting dashboard-container section">
                <div className="device-details z-depth-0">
                    <div className="card-content">
                        <p className="card-title"> Name - {deviceName} </p>
                        <p> Date/Time - {localTime} </p>
                        <p> Battery Percent - {device.battery} </p>
                        <p> Moisture Percent - {device.soilMoisturePercent} </p>
                    </div>
                    <div className="card-action grey lighten-4 grey-text">
                        <input type="date" defaultValue={today} max={today} onChange={(event => handleChange(event.target.value))}/>
                        <Line data={chartData} options={options}/>
                    </div>
                </div>
            </div>
        )
    }
}

const mapStateToProps = (state, ownProps) => {
    const id = ownProps.match.params.id;
    const devices = state.device.devices;
    const sensors = state.device.sensorData;
    const device = devices ? devices[id] : null
    const deviceName = state.auth.user.devices[id].Value
    const sensorData = sensors ? sensors[id] : null
    return {
        auth: state.firebase.auth,
        device: device,
        sensorData: sensorData,
        deviceName: deviceName,
    }
}

export default connect(mapStateToProps)(DeviceDetails)

After Change to Class Component

import React, {Component} from 'react'
import {Redirect} from "react-router-dom";
import {connect} from 'react-redux'
import {Line} from "react-chartjs-2";
import moment from "moment";
import "./DeviceDetails.css"
import axios from "axios";
import {updateDeviceName} from "../../store/Actions/AuthActions";

class DeviceDetails extends Component {
    constructor(props) {
        super(props);
        this.state = {
            chartData: {},
            options: {...},
            devName: this.props.deviceName,
            deviceId: this.props.device.deviceId
        }
    }

    componentDidMount = () => {
        const {sensorData} = this.props

        let chartData = {}

        if (sensorData) {
            chartData = sensorData.map(data => {
                const container = {};
                container.x = moment(data.dateTime)
                container.y = data.soilMoisturePercent
                return container
            })
        }

        this.setState({
            chartData: {
                labels: [moment().startOf('day'), moment().endOf('day')],
                datasets: [
                    {
                        label: "Moisture Levels",
                        data: chartData,
                        backgroundColor: ['rgba(75,192,192,0.6)'],
                        borderWidth: 4
                    }
                ],
            }
        })
    }

    handleNameChange = (event) => {
        this.setState({
            devName: event.target.value
        })
    }

    updateDeviceName = () => {
        this.props.updateDeviceName(this.state)
    }

    render() {
        const {auth, device} = this.props
        const today = moment().format().split("T")[0]
        const localTime = moment(device.dateTime).format("DD/MM/YYYY HH:mm").toString()

        if (!auth.uid) {
            return <Redirect to="/signin"/>
        } else {
            return (
                <form>
                    <div className="fitting dashboard-container section">
                        <div className="device-details z-depth-0">
                            <div className="card-content">
                                <input type="text" id="devName" value={this.state.devName}
                                       onChange={this.handleNameChange} onBlur={this.updateDeviceName}/>
                                <p> Date/Time - {localTime} </p>
                                <p> Battery Percent - {device.battery} </p>
                                <p> Moisture Percent - {device.soilMoisturePercent} </p>
                            </div>
                            <div className="card-action grey lighten-4 grey-text">
                                <input type="date" defaultValue={today} max={today}
                                       onChange={(event => this.handleChange(event.target.value))}/>
                                <Line data={this.state.chartData} options={this.state.options}/>
                            </div>
                        </div>
                    </div>
                </form>
            )
        }
    }
}

const mapStateToProps = (state, ownProps) => {
    const id = ownProps.match.params.id;
    const devices = state.device.devices;
    const sensors = state.device.sensorData;
    const device = devices ? devices[id] : null
    const deviceName = state.auth.user.devices[id].Value.toString()
    const sensorData = sensors ? sensors[id] : null
    return {
        auth: state.firebase.auth,
        device: device,
        sensorData: sensorData,
        deviceName: deviceName,
    }
}

const mapDispatchToProps = (dispatch) => {
    return {
        updateDeviceName: (device) => dispatch(updateDeviceName(device))
    }
}

export default connect(mapStateToProps, mapDispatchToProps)(DeviceDetails)

1

There are 1 answers

0
Nikster On BEST ANSWER

Well..... I found the answer... The errors are different but it fixed everything

react-chartjs state update error

Adding redraw prop to my fixed all the issues...