I am new to React and I want to see if my design logic is correct.
I wish to animate a grid. A grid is composed of lines.
Therefore, I have defined a <Grid />
component and a child component <Gridline \>
.
I figured that each <Gridline />
should handle its own animation logic. The <Grid \>
parent component should be responsible for positioning the <Gridline />
components.
After all of the <Gridline \>
's have finished animating, I want all of the gridlines to fade away. I figured this fade away logic should be handled by the <Grid />
component. However, in order for <Grid />
to begin animating it must know when each <Gridline />
has concluded animating. This requires each <Gridline />
communicating to <Grid />
when it has finished animating. I think this is considered bad-practice in React as data should flow from parent to child. My question is: Is my design logic good(for example having a Grid component and a Gridline child component), and if not, how can I refactor my code so that data flows from the parent component to the child component?.
Here is the full code for reference
Grid.js
class Grid extends React.Component {
renderLines(numLines, offset, isRow) {
let ruledPos;
let offsetPos;
let duration;
let delay;
let spacing = Math.floor(100/numLines);
let lineType = isRow ? 'row' : 'col';
let lines = [];
for (let i = 1; i <= numLines; i++) {
ruledPos = offset + i * spacing;
offsetPos = Math.random() * 100;
duration = 100 + Math.random() * this.props.duration;
delay = 700 + Math.random() * this.props.delay;
lines.push(
<Gridline
key = {i + i*isRow}
lineType = {lineType}
offsetPos = {offsetPos}
ruledPos = {ruledPos}
duration = {duration}
delay = {delay}
/>
);
}
return lines;
}
render() {
let rowLines = this.renderLines(this.props.numLinesRow,
this.props.offset,
1);
let colLines = this.renderLines(this.props.numLinesCol,
this.props.offset,
0);
return(
<CSSTransition
in = {true}
appear = {true}
classNames = 'fade-out'
timeout = {this.props.duration + this.props.delay}>
<div className = 'grid' style = {{transitionDelay: `${300 + this.props.duration + this.props.delay}ms`}}>
{rowLines}
{colLines}
</div>
</CSSTransition>
);
}
}
Grid.defaultProps = {
numLinesRow: 15,
numLinesCol: 23,
offset: 0,
duration: 1000,
delay: 2000
};
export default Grid;
Gridline.js
import React from 'react';
import { CSSTransition } from 'react-transition-group';
class Gridline extends React.Component{
constructor(props){
super(props);
this.state = {
showGridline: true,
hasEntered: false
};
if (this.props.lineType === 'row') {
this.style = {'top': `${this.props.ruledPos}%`,
'left': `${this.props.offsetPos}%`,
};
} else {
this.style = {'left': `${this.props.ruledPos}%`,
'top': `${this.props.offsetPos}%`};
}
this.style.transitionDuration = `${this.props.duration}ms`;
this.style.transitionDelay = `${this.props.delay}ms`;
}
render(){
return(
<CSSTransition
in = {true}
appear = {true}
classNames = {`line-${this.props.lineType}`}
timeout={this.props.duration + this.props.delay}
>
<div
className = "line"
style = {this.style}>
</div>
</CSSTransition>
);
}
}
export default Gridline;
App.js
import React from 'react'
import './css/index.css'
import './css/materialize.css'
import Grid from './components/Grid.js'
class App extends React.Component{
render() {
return (
<div id = 'App'>
<Grid />
</div>
)
}
}
export default App