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
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)
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...