React/Redux Carousel - javascript

So I am creating my own site for my resume and have run up against an issue I'm not exactly sure how to solve. I am using React and Redux, the issue comes up that what I want is to display small little projects in a carousel type format using react with proper redux integrated in. Currently my file structure looks like:
src/
actions/
index.js
components/
App.js
NavBar.js
Projects.js
projects/
Project1/
Project2/
containers/
Main.js
reducers/
index.js
projects.js
I am not sure exactly how to accomplish what I want, I have searched for a good solution, but haven't really come across anything yet. I am still relatively new to react. What I don't want is to display one project, scroll down display the next, scroll some more... What I have tried is:
let components = [{TicTacToe}, {}];
let index = 0;
export default class Projects extends React.Component {
constructor(props) {
super(props);
this.state = {
component: components[0]
};
}
renderProject(i)
{
this.setState({component: components[i]});
}
backRotate()
{
index--;
if(index < 0)
{
index = components.length - 1;
}
this.renderProject(index);
}
forwardRotate()
{
index++;
if(index >= components.length)
{
index = 0;
}
this.renderProject(index);
}
render() {
return(
<div>
<button onClick='backRotate'>Back</button>
<div class='carousel-container'>
<this.state.component />
</div>
<button onClick='forwardRotate'>Next</button>
</div>
) }
}
I originally thought this would work, but it does break. I am currently running through App.js in my components folder adding the NavBar component and then adding the Main.js container. The reason for this container was the fact that I need a back and forward button to rotate through each project just like a carousel of images. I have considered adding all components and then just hiding and revealing, but this seems like a needless waste of resources and that there should be a better way to accomplish this.
Is there a way to replace a component on a button click? Completely remove the original component and add the new component in? If so, how do I also accomplish this using redux? Currently my projects reducer is just a place holder.

First of all, it breaks because the componentsarray contains objects, and React can't have that.
A valid React element is either a node (HTMLElement, React Component, text or number) or an array of nodes.
If you just want to keep React components in a collection and be able to select which is displayed, first you have to remove the braces in the components array, like so:
let components = [TicTacToe, AnotherComponent];
And you will also need to fix your backRotateand forwardRotate handlers. They can't be string like in html (note the braces instead of quotes):
<button onClick={this.backRotate}>Back</button>
<button onClick={this.forwardRotate}>Next</button>
...and must be bound to your component instance. A way to bind them is to use the Function.prototype.bind method. It should be done in the constructor:
constructor(props) {
super(props);
this.backRotate = this.backRotate.bind(this);
this.forwardRotate= this.forwardRotate.bind(this);
}
Without binding this would not be a reference to your component instance and calling this within the handlers would definitely fail.
TicTacToe and AnotherComponent must be classes extending React.Component or React.PureComponent, or must be pure functional components of props.
Also, its clearer and may be more supported to declare a capitalized variable containing the component:
render() {
const Comp = this.state.component;
return (
<div>
<button onClick={this.backRotate}>Back</button>
<div class='carousel-container'>
<Comp />
</div>
<button onClick={this.forwardRotate}>Next</button>
</div>
);
}
Finally, you should make index a state of your component (it's changed with the controls of the component) and components a prop (it does not change within the component).
Instead of setting the current component in state you will set the current component index:
import React from 'react':
import PropTypes from 'prop-types';
import { TicTacToe, AnotherComponent } from 'path/to/named/imports/TicTacToeAndAnotherComponent';
export default class Projects extends React.Component {
static propTypes = {
components: PropTypes.any,
}
static defaultProps = {
components: [TicTacToe, AnotherComponent],
}
constructor(props) {
super(props);
this.state = {
index: 0,
};
this.backRotate = this.backRotate.bind(this);
this.forwardRotate= this.forwardRotate.bind(this);
}
backRotate() {
const { components } = this.props;
const { index } = this.state;
if(index - 1 < 0) {
this.setState(() => ({ index: components.length - 1 }));
} else {
this.setState(() => ({ index: index - 1 }));
}
}
forwardRotate() {
const { components } = this.props;
const { index } = this.state;
if(index >= components.length) {
this.setState(() => ({ index: 0 }));
} else {
this.setState(() => ({ index: index + 1 }));
}
}
render() {
const Comp = this.props.components[this.state.index];
return (
<div>
<button onClick={this.backRotate}>Back</button>
<div class='carousel-container'>
<Comp />
</div>
<button onClick={this.forwardRotate}>Next</button>
</div>
);
}
}
Either way Redux won't help you with that.
The purpose of Redux is mainly to provide a single source of data (single source of truth), provide actions and reducers to mutate this data, and notify components registered to listen to store updates. Weither you connect your carousel to the store or not isn't really relevant to resolve your iisue.

Related

Material UI DataGrid set default selected row in a class?

I'm currently rewriting my datagrid component to us Material UI, all of my components so far are class components (due to project scope).
One thing that I am at a standstill on is how to have the DataGrid have the first row selected by default.
I already have a way to get the ID Of row and pass it down, but I am unsure how to implement that function in my project.
I was looking at this as an example, but it is a functional component. https://material-ui-x.netlify.app/storybook/?path=/story/x-grid-tests-selection--api-pre-selected-rows&globals=measureEnabled:false
the apiRef in DataGrid uses UseGridApiRef with selectRow()/selectRows() . The problem is, that is a functional hook, and cannot be used in a class directly. What would be the best way for me to implement such a function in my current code? I found very minimal documentation on this specific topic with MUI's datagrid.
import React from 'react';
import {DataGrid} from "#mui/x-data-grid";
class UniversalDataGrid extends React.Component {
constructor(props) {
super(props);
this.state = {
ownerDatabaseRows: [],
ownerDatabaseColumns: this.props.displayColumns,
selectionModel: [],
};
}
componentDidMount() {
if (this.props.sourceData !== 0) {
let rowData = this.props.sourceData;
this.setState({ownerDatabaseRows: rowData});
}
}
rowSelectionData = (selectedRow) => {
this.setState({selectionModel: selectedRow.row});
this.props.onRowClick(selectedRow);
};
render() {
let headerHeight = this.props.headerHeight === 'default' ? 56 : this.props.headerHeight;
let rowHeight = this.props.rowHeight !== "default" ? this.props.rowHeight : 56;
return (
<div style={{height: 200, width: '100%'}}>
<DataGrid
columns={this.props.displayColumns}
rows={this.state.ownerDatabaseRows}
onRowClick={this.rowSelectionData}
hideFooter={this.props.hideFooter}
headerHeight={headerHeight}
rowHeight={rowHeight}
/>
</div>
);
};
}
export default UniversalDataGrid;
I can easily pass another prop for the rowID to be selected by default, as there is code that runs wherever this component is called one level higher. I just need a way to use apiRef and UseGridApiRef.
I've had very little experience with functional components, so I'm not sure how to proceed in this case.

Which of these strategies is the best way to reset a component's state when the props change

I have a very simple component with a text field and a button:
It takes a list as input and allows the user to cycle through the list.
The component has the following code:
import * as React from "react";
import {Button} from "#material-ui/core";
interface Props {
names: string[]
}
interface State {
currentNameIndex: number
}
export class NameCarousel extends React.Component<Props, State> {
constructor(props: Props) {
super(props);
this.state = { currentNameIndex: 0}
}
render() {
const name = this.props.names[this.state.currentNameIndex].toUpperCase()
return (
<div>
{name}
<Button onClick={this.nextName.bind(this)}>Next</Button>
</div>
)
}
private nextName(): void {
this.setState( (state, props) => {
return {
currentNameIndex: (state.currentNameIndex + 1) % props.names.length
}
})
}
}
This component works great, except I have not handled the case when the state changes. When the
state changes, I would like to reset the currentNameIndex to zero.
What is the best way to do this?
Options I have conciderred:
Using componentDidUpdate
This solution is ackward, because componentDidUpdate runs after render, so I need to add a clause
in the render method to "do nothing" while the component is in an invalid state, if I am not careful,
I can cause a null-pointer-exception.
I have included an implementation of this below.
Using getDerivedStateFromProps
The getDerivedStateFromProps method is static and the signature only gives you access to the
current state and next props. This is a problem because you cannot tell if the props have changed. As
a result, this forces you to copy the props into the state so that you can check if they are the same.
Making the component "fully controlled"
I don't want to do this. This component should privately own what the currently selected index is.
Making the component "fully uncontrolled with a key"
I am considering this approach, but don't like how it causes the parent to need to understand the
implementation details of the child.
Link
Misc
I have spent a great deal of time reading You Probably Don't Need Derived State
but am largely unhappy with the solutions proposed there.
I know that variations of this question have been asked multiple times, but I don't feel like any of the answers weigh the possible solutions. Some examples of duplicates:
How to reset state in a component on prop change
Update component state when props change
Updating state on props change in React Form
Appendix
Solution using componetDidUpdate (see description above)
import * as React from "react";
import {Button} from "#material-ui/core";
interface Props {
names: string[]
}
interface State {
currentNameIndex: number
}
export class NameCarousel extends React.Component<Props, State> {
constructor(props: Props) {
super(props);
this.state = { currentNameIndex: 0}
}
render() {
if(this.state.currentNameIndex >= this.props.names.length){
return "Cannot render the component - after compoonentDidUpdate runs, everything will be fixed"
}
const name = this.props.names[this.state.currentNameIndex].toUpperCase()
return (
<div>
{name}
<Button onClick={this.nextName.bind(this)}>Next</Button>
</div>
)
}
private nextName(): void {
this.setState( (state, props) => {
return {
currentNameIndex: (state.currentNameIndex + 1) % props.names.length
}
})
}
componentDidUpdate(prevProps: Readonly<Props>, prevState: Readonly<State>): void {
if(prevProps.names !== this.props.names){
this.setState({
currentNameIndex: 0
})
}
}
}
Solution using getDerivedStateFromProps:
import * as React from "react";
import {Button} from "#material-ui/core";
interface Props {
names: string[]
}
interface State {
currentNameIndex: number
copyOfProps?: Props
}
export class NameCarousel extends React.Component<Props, State> {
constructor(props: Props) {
super(props);
this.state = { currentNameIndex: 0}
}
render() {
const name = this.props.names[this.state.currentNameIndex].toUpperCase()
return (
<div>
{name}
<Button onClick={this.nextName.bind(this)}>Next</Button>
</div>
)
}
static getDerivedStateFromProps(props: Props, state: State): Partial<State> {
if( state.copyOfProps && props.names !== state.copyOfProps.names){
return {
currentNameIndex: 0,
copyOfProps: props
}
}
return {
copyOfProps: props
}
}
private nextName(): void {
this.setState( (state, props) => {
return {
currentNameIndex: (state.currentNameIndex + 1) % props.names.length
}
})
}
}
As i said in the comments, i'm not a fan of these solutions.
Components should not care what the parent is doing or what is the current state of the parent, they should simply take in props and output some JSX, this way they are truly reusable, composable and isolated which also makes testing a lot easier.
We can make the NamesCarousel component hold the names of the carousel together with the functionality of the carousel and the current visible name and make a Name component which does only one thing, display the name that comes in through props
To reset the selectedIndex when the items are changing add a useEffect with items as a dependency, although if you just add items to the end of the array you can ignore this part
const Name = ({ name }) => <span>{name.toUpperCase()}</span>;
const NamesCarousel = ({ names }) => {
const [selectedIndex, setSelectedIndex] = useState(0);
useEffect(() => {
setSelectedIndex(0)
}, [names])// when names changes reset selectedIndex
const next = () => {
setSelectedIndex(prevIndex => prevIndex + 1);
};
const prev = () => {
setSelectedIndex(prevIndex => prevIndex - 1);
};
return (
<div>
<button onClick={prev} disabled={selectedIndex === 0}>
Prev
</button>
<Name name={names[selectedIndex]} />
<button onClick={next} disabled={selectedIndex === names.length - 1}>
Next
</button>
</div>
);
};
Now this is fine but is the NamesCarousel reusable? no, the Name component is but the Carousel is coupled with the Name component.
So what can we do to make it truly reusable and see the benefits of designing component in isolation?
We can take advantage of the render props pattern.
Lets make a generic Carousel component which will take a generic list of items and invoke the children function passing in the selected item
const Carousel = ({ items, children }) => {
const [selectedIndex, setSelectedIndex] = useState(0);
useEffect(() => {
setSelectedIndex(0)
}, [items])// when items changes reset selectedIndex
const next = () => {
setSelectedIndex(prevIndex => prevIndex + 1);
};
const prev = () => {
setSelectedIndex(prevIndex => prevIndex - 1);
};
return (
<div>
<button onClick={prev} disabled={selectedIndex === 0}>
Prev
</button>
{children(items[selectedIndex])}
<button onClick={next} disabled={selectedIndex === items.length - 1}>
Next
</button>
</div>
);
};
Now what this pattern actually gives us?
It gives us the ability to render the Carousel component like this
// items can be an array of any shape you like
// and the children of the component will be a function
// that will return the select item
<Carousel items={["Hi", "There", "Buddy"]}>
{name => <Name name={name} />} // You can render any component here
</Carousel>
Now they are both isolated and truly reusable, you can pass items as an array of images, videos, or even users.
You can take it further and give the carousel the number of items you want to display as props and invoke the child function with an array of items
return (
<div>
{children(items.slice(selectedIndex, selectedIndex + props.numOfItems))}
</div>
)
// And now you will get an array of 2 names when you render the component
<Carousel items={["Hi", "There", "Buddy"]} numOfItems={2}>
{names => names.map(name => <Name key={name} name={name} />)}
</Carousel>
Can you use a functional component? Might simplify things a bit.
import React, { useState, useEffect } from "react";
import { Button } from "#material-ui/core";
interface Props {
names: string[];
}
export const NameCarousel: React.FC<Props> = ({ names }) => {
const [currentNameIndex, setCurrentNameIndex] = useState(0);
const name = names[currentNameIndex].toUpperCase();
useEffect(() => {
setCurrentNameIndex(0);
}, names);
const handleButtonClick = () => {
setCurrentIndex((currentNameIndex + 1) % names.length);
}
return (
<div>
{name}
<Button onClick={handleButtonClick}>Next</Button>
</div>
)
};
useEffect is similar to componentDidUpdate where it will take an array of dependencies (state and prop variables) as the second argument. When those variables change, the function in the first argument is executed. Simple as that. You can do additional logic checks inside of the function body to set variables (e.g., setCurrentNameIndex).
Just be careful if you have a dependency in the second argument that gets changed inside the function, then you will have infinite rerenders.
Check out the useEffect docs, but you'll probably never want to use a class component again after getting used to hooks.
You ask what is the best option, the best option is to make it a Controlled component.
The component is too low in the hierarchy to know how to handle it's properties changing - what if the list changed but only slightly (perhaps adding a new name) - the calling component might want to keep the original position.
In all cases I can think about we are better off if the parent component can decide how the component should behave when provided a new list.
It's also likely that such a component is part of a bigger whole and needs to pass the current selection to it's parent - perhaps as part of a form.
If you are really adamant on not making it a controlled component, there are other options:
Instead of an index you can keep the entire name (or an id component) in the state - and if that name no longer exists in the names list, return the first in the list. This is a slightly different behavior than your original requirements and might be a performance issue for a really really really long list, but it's very clean.
If you are ok with hooks, than useEffect as Asaf Aviv suggested is a very clean way to do it.
The "canonical" way to do it with classes seems to be getDerivedStateFromProps - and yes that means keeping a reference to the name list in the state and comparing it. It can look a bit better if you write it something like this:
static getDerivedStateFromProps(props: Props, state: State = {}): Partial<State> {
if( state.names !== props.names){
return {
currentNameIndex: 0,
names: props.names
}
}
return null; // you can return null to signify no change.
}
(you should probably use state.names in the render method as well if you choose this route)
But really - controlled component is the way to go, you'll probably do it sooner or later anyway when demands change and the parent needs to know the selected item.

How to pass a state to multiple other classes in React

I started learning React approx. month ago and I'm very confused about the concept because its still something new to me(compared to my previous work in C++ and C).
To quickly summarize I would like to know what is React's equivalent of C++ return form a function. How would I return value(or values) from a function(in my case class functions/states) and use it in my other components.
I have made an simple script that changes background to simulate RGB light on mouse and I made it so the HSL color mode is applied to the background of the component. I would like to use this on multiple components,icons, etc on my page but it feels like there is a better way than importing all functions in three files making the work triple than requiered.
import React, { Component } from 'react'
import './colorStrip.scss'
class ColorStrip extends Component {
constructor(props) {
super(props)
this.colorHue=10;
this.colorSaturation=100;
this.colorLightness=50;
this.state = {
color:"hsl(0,100%,50%)"
}
this.changeColor(1);
}
changeColor = (speed) => {
this.colorHue+=10*speed;
if(this.colorHue>=360)
this.colorHue=0;
this.setState({
color : "hsl("+this.colorHue+","+this.colorSaturation+"%,"+this.colorLightness+"%)"
})
setTimeout(() => {this.changeColor(speed)},75)
}
render() {
return (
<svg style={{backgroundColor:this.state.color}} className="strip">
</svg>
)
}
}
export default ColorStrip
So I would like to use this.state.color(or this.state.colorHue or any state) in three other SVG components on my page.
I really looked some of the other answers but they were quite complex and requiered multiple returns which was confusing.
There are a couple different options you can use to achieve this.
One would be to move your function that calculates the colour to a higher level component (so one of the parent components), that has the child components you want to pass this state to, and then pass your state down through component props.
class parent extends component {
// your functions to calculate your colour
render () {
return <div>
<ChildComponent colourProp={this.state.color} />
<ChildComponent colourProp={this.state.color} />
<ChildComponent colourProp={this.state.color} />
</div>
}
}
Another option if you need the colour to change based on the child component, is to pass down the function that alters the colour to the child component. So similar to the example above, but you would pass down the colour changing function to the child as well.
<ChildComponent colourProp={this.state.color} changeColour={this.changeColourFunction}/>
Now you can call that function from your child
// Inside child component
this.props.changeColour(params)
And now your parent will change its state, and the new colour will get changed in the parent and passed down to all the children.
Lastly you can try using ReactContext, set it up in a file that's external to all your components and and import it to your components. In your parent component where you pass your initial state, you would use YourContext.Provider and pass your initial state. Then in your children you can use YourContext.Consumer. For more details on this see : https://reactjs.org/docs/context.html
As Jonathan said, you can pass state as props to other components, but only if they are connected. If the svgs you are using are not being rendered in the same file, things will become a little messy. In order to 'fix' this, people use state management tools, such as redux and context API.
Redux, for example, is built based on database design, so you can access the state globally. Tough it is really useful, the environment is not beginners friendly, and I do not advise you learning it until completely grasping react.
Try this way:
import './colorStrip.scss'
class ColorStrip extends Component {
constructor(props) {
super(props)
this.colorHue=10;
this.colorSaturation=100;
this.colorLightness=50;
this.state = {
color:"hsl(0,100%,50%)"
}
this.changeColor(1);
}
changeColor = (speed) => {
this.colorHue+=10*speed;
if(this.colorHue>=360)
this.colorHue=0;
this.setState({
color : "hsl("+this.colorHue+","+this.colorSaturation+"%,"+this.colorLightness+"%)"
})
setTimeout(() => {this.changeColor(speed)},75)
}
render() {
const { color } = this.props;
return (
<svg style={backgroundColor:color} className="strip">
</svg>
)
}
}
export default ColorStrip
I'd suggest creating a Higher-Order Component (HOC) to house the color logic and then you can wrap any component you want with this HOC and the wrapped component will have the logic & data you need.
For example:
import React, { Component } from "react";
function withColor(WrappedComponent) {
return class ComponentWithColor extends Component {
constructor(props) {
super(props);
this.colorHue=10;
this.colorSaturation=100;
this.colorLightness=50;
this.state = {
color:"hsl(0,100%,50%)"
}
this.changeColor(1);
}
changeColor = (speed) => {
this.colorHue+=10*speed;
if(this.colorHue>=360)
this.colorHue=0;
this.setState({
color : "hsl("+this.colorHue+","+this.colorSaturation+"%,"+this.colorLightness+"%)"
})
setTimeout(() => {this.changeColor(speed)},75)
}
render() {
const { color } = this.state;
return <WrappedComponent color={ color } { ...this.props }/>
}
}
}
Then if you define a new component, and you want it to have access to the color prop, just wrap the component class/function in withColor before constructing.
For example:
class MyComponent extends Component {
render() {
const { color } = this.props;
return (
<svg style={backgroundColor:color} className="strip">
</svg>
)
}
}
const MyComponentWithColor = withColor(MyComponent);
// then export & use MyComponentWithColor

How do I access a React Class method from outside?

Lets say I have a component defined like this -
// actioncomponent.js
import React from 'react';
class ActionComponent extends React.Component {
state = {
isAction: false;
}
doAction = () => {
this.setState({isAction: true})
}
render () {
return (
<div>
Some render stuff..
</div>
)
}
}
export default ActionComponent
From another completely different file I want to set the state for the first component without rendering it in the new file so I need not use refs or props.
// newfile.js
import ActionComponent from './actioncomponent.js'
ActionComponent.doAction()
I'm aware the doAction can't be exported and calling it static doesn't have access to state either. How do I achieve something like this?
In React ecosystem you probably don't need this.
You can pass this method to a child component:
class ActionComponent extends React.Component {
state = {
isAction: false
}
doAction = () => {
this.setState({isAction: true})
}
render () {
return (
<div>
<Child doAction={this.doAction} />
</div>
)
}
}
And then in a Child component you can fire this action
// ...
render() {
<button onClick={() => props.doAction()}>Test</button>
}
If you need to fire action on parent, instead of child you might want to structure your state on upper level, or lift state up.
You can also achieve similar goal without drilling props, but you'll need some state management tool, e.g. Redux or in some cases Context API would be a great fit.

Why is the child component updating but not re-render Reactjs

I have a main component with a child chart component. On connecting to a websocket, the main component updates the state of the child chart component. This however does not redraw. When I click on the chart however, the labels appear, and when I click again, the values appear with the labels.
Main.js:
import IO from 'socket.io-client';
import React from "react";
import { Switch, Route } from 'react-router-dom';
import { Chart } from "./Chart";
let ftse100Tickers = require('./ftse_100_tickers.json');
let randomInt = Math.floor(Math.random() * ftse100Tickers.tickers.length);
/**
* Main application component which contains
*/
export class Main extends React.Component {
componentWillMount() {
this.socket = IO(location.protocol + "//" + document.domain + ":" + location.port);
this.socket.on("connect", (() => this.connect()));
this.socket.on("disconnect", (() => this.disconnect()));
this.socket.on("initial data", ((data) => this.createInitialChart(data)))
}
connect(){
this.setState({status: 'connected'});
this.socket.emit("get initial data", this.state.ticker);
}
disconnect(){
this.setState({status: 'disconnected'})
}
createInitialChart(data){
let tempErrorChart= this.state.errorChart;
for (let row of data){
tempErrorChart.labels.push(row.time_stamp);
tempErrorChart.datasets[0].data.push(row.error);
}
this.setState({errorChart: tempErrorChart});
}
constructor(props){
super(props);
this.state = {
errorChart: {
labels: [],
datasets: [
{
label: 'Error',
data: [],
},
]
},
status: 'disconnected',
ticker : ftse100Tickers.tickers[randomInt],
twitter : ftse100Tickers.twitter[randomInt]
}
}
render() {
return (
<div className="row">
<div className="row">
<div className="col-lg-6">
<div className="card border-0">
<div className="card-body">
<Chart chart={this.state.errorChart}/>
</div>
</div>
</div>
</div>
</div>
)
}
}
The chart component is as so:
Chart.js
import { Line } from "react-chartjs-2"
import React from "react";
/*
* General charting component used for rendering charts
*/
export class Chart extends React.Component {
render() {
return (
<Line data={this.props.chart} options={{}}/>
)
}
}
I see one problem and that is you are not changing object references in this.state.errorChart upon errorChart update before you call setState. Even though you push to its properties new items, the object and even the inner array references do not change, and if the Line component does some props checking on whether it should rerender itself or not, it figures by receiving still the same references that nothing has changed and there is no need to rerender.
Now this was just my assumption, but either way it is a good practice to always create new objects while creating new state once those objects are about to be modified. This allows for fast object (state) references comparisons in shouldComponentUpdate methods or while using PureComponentwhich in turn makes it easier and more performant to determine whether to rerender the component or not. On the other hand, if you would use the same references still, you would have to implement deep comparison of the old and the new state, which is definitely more expensive and very fragile in the long run.
Example on how to correctly update the state follows:
createInitialChart(data) {
const errorChart = this.state.errorChart
const newErrorChart = {
...errorChart
}
newErrorChart.labels = [...errorChart.labels, data.map(row => row.time_stamp)]
newErrorChart.datasets[0].data = [
...errorChart.datasets[0].data,
data.map(row => row.error)
]
this.setState({ errorChart: newErrorChart })
}
Edit:
By looking at the component's shouldComponentUpdate implementation - ChartComponent, It can be clearly seen, that there are multiple options on how to make the Line rerender, eg. by giving redraw={true} prop to the Line component. The procedure above is generally still the safest way to ensure rerender though.
You might need componentWillReceiveProps(nextProps, nextState).
You can compare the old state here with the new state and update the state accordingly.
Please set the initialState like so:
constructor(props){
super(props);
this.state = {errorChart: {...}}; //your initial values here.
}
then,
componentWillReceiveProps(nextProps, nextState){
if(this.state.errorChart !== nextState.errorChart){
let tempErrorChart = {...this.state.errorChart};
for (let row of data){
tempErrorChart.labels.push(row.time_stamp);
tempErrorChart.datasets[0].data.push(row.error);
}
this.setState({errorChart: tempErrorChart});
}
}

Categories