Reputation: 867
I want to create a simple calculator app in React, which is consisted out of 3 main components: App.js, Buttons.js, and Display.js.
App is the parent for both Display and Buttons. Display is above the Buttons, and according to the button click, Display's state should change. I'm passing the onClick function as prop to the Buttons, and even though the App's state changes, Display components doesn't re-render.
I will paste my code and due simplicity, remove most of the logic and leave only one button('1'). So, the press on that button should display '1'. Code:
App.js:
import React, { Component } from 'react';
import './App.css';
import Buttons from './components/Buttons';
import Display from './components/Display';
class App extends Component {
constructor(props) {
super(props);
this.state = {
display: "0"
}
}
handleClick = e => {
this.setState({ display: e.target.value });
}
render() {
return (
<div className="container border border-success main-div">
<Display display={this.state.display}/>
<Buttons handleClick={this.handleClick} />
</div>
);
}
}
export default App;
Display.js:
import React, { Component } from 'react';
class Display extends Component {
constructor(props) {
super(props);
this.state = {
display: "0"
}
}
componentDidMount = () => {
this.setState({ display: this.props.display })
}
render() {
return (
<div className="row border border-success">
<div className="col">
{this.state.display}
</div>
</div>
);
}
}
export default Display;
Buttons.js:
import React, { Component } from 'react';
class Buttons extends Component {
constructor(props) {
super(props);
}
render() {
return (
<div className="row">
<div className="col-sm border border-success">
<div className="calc-button" data-value="1" onClick={this.props.handleClick}>1</div>
</div>
</div>
);
}
}
export default Buttons;
What am I doing wrong? What's the other way of implementing this if this one isn't right?
Upvotes: 2
Views: 39
Reputation: 3407
Either you can go with Simone's answer
or you can use static getDerivedStateFromProps()
Display component probably will look like this:
class Display extends Component {
constructor(props) {
super(props);
this.state = {
display: "0"
}
}
// wrong placement
// componentDidMount = () => {
// this.setState({ display: this.props.display })
// }
static getDerivedStateFromProps(nextProps, prevState) {
// do things with nextProps.display
// You can use static getDerivedStateFromProps and return a new state based on changes on props.
return {
display: nextProps.display
};
}
//If you need to perform a side effect (for example, data fetching or an animation)
// in response to a change in props, use componentDidUpdate lifecycle instead.
render() {
return (
<div className="row border border-success">
<div className="col">
{this.state.display}
</div>
</div>
);
}
}
export default Display;
Upvotes: 1
Reputation: 21282
You can rewrite your Display
component to be as simple as:
import React, { Component } from 'react';
export default class Display extends Component {
render() {
return (
<div className="row border border-success">
<div className="col">
{this.props.display}
</div>
</div>
);
}
}
Your example is not working because on Display you’re setting some internal component state, and then displaying it. The value you're looking for has been passed via props.
Upvotes: 2