React calculator












5















My company is going to make a big leap soon, and since we are currently still running on AngularJS 1.3.X we decided to make the switch to react for a myriad of reasons besides the obvious. Being the lead developer I decided to start messing around a bit.



After my first bit of research and hello world apps, I got to work on this calculator. It was made in about 30 minutes.



I was curious about my use of the state type properties, and if its the right way to tackle these kind of things. Any and all input is very much appreciated!



var Calculator = React.createClass({
getInitialState: function() {
return {
currentNumber: 0,
}
},
addDigit: function(n) {
if(this.state.currentNumber == 0){
this.setState({
currentNumber: n
})
} else {
this.setState({
currentNumber: "" + this.state.currentNumber + n
})
}
},
setOperator: function(f) {
if(this.state.currentNumber.slice(-1) != " "){
this.setState({
currentNumber: "" + this.state.currentNumber + " " + f + " "
})
}
},
solve: function() {
this.setState({
currentNumber: eval(this.state.currentNumber)
})
},
clear: function() {
this.setState({
currentNumber: 0
})
},
render: function() {
return (
<div>
<h1>This here Cal-Q-lator</h1>
<div>
<input value={this.state.currentNumber}/>
<div>
<button onClick={this.clear} className="btn-1">C</button>
<button onClick={()=>this.setOperator('/')} className="btn-1">/</button>
<button onClick={()=>this.setOperator('*')} className="btn-1">*</button>
<button onClick={()=>this.setOperator('-')} className="btn-1">-</button>
</div>
<div>
<button onClick={()=>this.addDigit(7)} className="btn-1">7</button>
<button onClick={()=>this.addDigit(8)} className="btn-1">8</button>
<button onClick={()=>this.addDigit(9)} className="btn-1">9</button>
<button onClick={()=>this.setOperator('+')} className="btn-1">+</button>
</div>
<div>
<button onClick={()=>this.addDigit(4)} className="btn-1">4</button>
<button onClick={()=>this.addDigit(5)} className="btn-1">5</button>
<button onClick={()=>this.addDigit(6)} className="btn-1">6</button>
<button onClick={()=>this.setOperator('+')} className="btn-1">+</button>
</div>
<div>
<button onClick={()=>this.addDigit(1)} className="btn-1">1</button>
<button onClick={()=>this.addDigit(2)} className="btn-1">2</button>
<button onClick={()=>this.addDigit(3)} className="btn-1">3</button>
<button onClick={this.solve} className="btn-1">E</button>
</div>
<div>
<button onClick={()=>this.addDigit(0)} className="btn-1">0</button>
<button onClick={()=>this.addDigit(0)} className="btn-1">0</button>
<button onClick={()=>this.addDigit('.')} className="btn-1">.</button>
<button onClick={this.solve} className="btn-1">E</button>
</div>
</div>
</div>
)
}
});

ReactDOM.render(
<Calculator />,
document.getElementById('root1')
);


I used React, ReactDOM and Babel.










share|improve this question





























    5















    My company is going to make a big leap soon, and since we are currently still running on AngularJS 1.3.X we decided to make the switch to react for a myriad of reasons besides the obvious. Being the lead developer I decided to start messing around a bit.



    After my first bit of research and hello world apps, I got to work on this calculator. It was made in about 30 minutes.



    I was curious about my use of the state type properties, and if its the right way to tackle these kind of things. Any and all input is very much appreciated!



    var Calculator = React.createClass({
    getInitialState: function() {
    return {
    currentNumber: 0,
    }
    },
    addDigit: function(n) {
    if(this.state.currentNumber == 0){
    this.setState({
    currentNumber: n
    })
    } else {
    this.setState({
    currentNumber: "" + this.state.currentNumber + n
    })
    }
    },
    setOperator: function(f) {
    if(this.state.currentNumber.slice(-1) != " "){
    this.setState({
    currentNumber: "" + this.state.currentNumber + " " + f + " "
    })
    }
    },
    solve: function() {
    this.setState({
    currentNumber: eval(this.state.currentNumber)
    })
    },
    clear: function() {
    this.setState({
    currentNumber: 0
    })
    },
    render: function() {
    return (
    <div>
    <h1>This here Cal-Q-lator</h1>
    <div>
    <input value={this.state.currentNumber}/>
    <div>
    <button onClick={this.clear} className="btn-1">C</button>
    <button onClick={()=>this.setOperator('/')} className="btn-1">/</button>
    <button onClick={()=>this.setOperator('*')} className="btn-1">*</button>
    <button onClick={()=>this.setOperator('-')} className="btn-1">-</button>
    </div>
    <div>
    <button onClick={()=>this.addDigit(7)} className="btn-1">7</button>
    <button onClick={()=>this.addDigit(8)} className="btn-1">8</button>
    <button onClick={()=>this.addDigit(9)} className="btn-1">9</button>
    <button onClick={()=>this.setOperator('+')} className="btn-1">+</button>
    </div>
    <div>
    <button onClick={()=>this.addDigit(4)} className="btn-1">4</button>
    <button onClick={()=>this.addDigit(5)} className="btn-1">5</button>
    <button onClick={()=>this.addDigit(6)} className="btn-1">6</button>
    <button onClick={()=>this.setOperator('+')} className="btn-1">+</button>
    </div>
    <div>
    <button onClick={()=>this.addDigit(1)} className="btn-1">1</button>
    <button onClick={()=>this.addDigit(2)} className="btn-1">2</button>
    <button onClick={()=>this.addDigit(3)} className="btn-1">3</button>
    <button onClick={this.solve} className="btn-1">E</button>
    </div>
    <div>
    <button onClick={()=>this.addDigit(0)} className="btn-1">0</button>
    <button onClick={()=>this.addDigit(0)} className="btn-1">0</button>
    <button onClick={()=>this.addDigit('.')} className="btn-1">.</button>
    <button onClick={this.solve} className="btn-1">E</button>
    </div>
    </div>
    </div>
    )
    }
    });

    ReactDOM.render(
    <Calculator />,
    document.getElementById('root1')
    );


    I used React, ReactDOM and Babel.










    share|improve this question



























      5












      5








      5








      My company is going to make a big leap soon, and since we are currently still running on AngularJS 1.3.X we decided to make the switch to react for a myriad of reasons besides the obvious. Being the lead developer I decided to start messing around a bit.



      After my first bit of research and hello world apps, I got to work on this calculator. It was made in about 30 minutes.



      I was curious about my use of the state type properties, and if its the right way to tackle these kind of things. Any and all input is very much appreciated!



      var Calculator = React.createClass({
      getInitialState: function() {
      return {
      currentNumber: 0,
      }
      },
      addDigit: function(n) {
      if(this.state.currentNumber == 0){
      this.setState({
      currentNumber: n
      })
      } else {
      this.setState({
      currentNumber: "" + this.state.currentNumber + n
      })
      }
      },
      setOperator: function(f) {
      if(this.state.currentNumber.slice(-1) != " "){
      this.setState({
      currentNumber: "" + this.state.currentNumber + " " + f + " "
      })
      }
      },
      solve: function() {
      this.setState({
      currentNumber: eval(this.state.currentNumber)
      })
      },
      clear: function() {
      this.setState({
      currentNumber: 0
      })
      },
      render: function() {
      return (
      <div>
      <h1>This here Cal-Q-lator</h1>
      <div>
      <input value={this.state.currentNumber}/>
      <div>
      <button onClick={this.clear} className="btn-1">C</button>
      <button onClick={()=>this.setOperator('/')} className="btn-1">/</button>
      <button onClick={()=>this.setOperator('*')} className="btn-1">*</button>
      <button onClick={()=>this.setOperator('-')} className="btn-1">-</button>
      </div>
      <div>
      <button onClick={()=>this.addDigit(7)} className="btn-1">7</button>
      <button onClick={()=>this.addDigit(8)} className="btn-1">8</button>
      <button onClick={()=>this.addDigit(9)} className="btn-1">9</button>
      <button onClick={()=>this.setOperator('+')} className="btn-1">+</button>
      </div>
      <div>
      <button onClick={()=>this.addDigit(4)} className="btn-1">4</button>
      <button onClick={()=>this.addDigit(5)} className="btn-1">5</button>
      <button onClick={()=>this.addDigit(6)} className="btn-1">6</button>
      <button onClick={()=>this.setOperator('+')} className="btn-1">+</button>
      </div>
      <div>
      <button onClick={()=>this.addDigit(1)} className="btn-1">1</button>
      <button onClick={()=>this.addDigit(2)} className="btn-1">2</button>
      <button onClick={()=>this.addDigit(3)} className="btn-1">3</button>
      <button onClick={this.solve} className="btn-1">E</button>
      </div>
      <div>
      <button onClick={()=>this.addDigit(0)} className="btn-1">0</button>
      <button onClick={()=>this.addDigit(0)} className="btn-1">0</button>
      <button onClick={()=>this.addDigit('.')} className="btn-1">.</button>
      <button onClick={this.solve} className="btn-1">E</button>
      </div>
      </div>
      </div>
      )
      }
      });

      ReactDOM.render(
      <Calculator />,
      document.getElementById('root1')
      );


      I used React, ReactDOM and Babel.










      share|improve this question
















      My company is going to make a big leap soon, and since we are currently still running on AngularJS 1.3.X we decided to make the switch to react for a myriad of reasons besides the obvious. Being the lead developer I decided to start messing around a bit.



      After my first bit of research and hello world apps, I got to work on this calculator. It was made in about 30 minutes.



      I was curious about my use of the state type properties, and if its the right way to tackle these kind of things. Any and all input is very much appreciated!



      var Calculator = React.createClass({
      getInitialState: function() {
      return {
      currentNumber: 0,
      }
      },
      addDigit: function(n) {
      if(this.state.currentNumber == 0){
      this.setState({
      currentNumber: n
      })
      } else {
      this.setState({
      currentNumber: "" + this.state.currentNumber + n
      })
      }
      },
      setOperator: function(f) {
      if(this.state.currentNumber.slice(-1) != " "){
      this.setState({
      currentNumber: "" + this.state.currentNumber + " " + f + " "
      })
      }
      },
      solve: function() {
      this.setState({
      currentNumber: eval(this.state.currentNumber)
      })
      },
      clear: function() {
      this.setState({
      currentNumber: 0
      })
      },
      render: function() {
      return (
      <div>
      <h1>This here Cal-Q-lator</h1>
      <div>
      <input value={this.state.currentNumber}/>
      <div>
      <button onClick={this.clear} className="btn-1">C</button>
      <button onClick={()=>this.setOperator('/')} className="btn-1">/</button>
      <button onClick={()=>this.setOperator('*')} className="btn-1">*</button>
      <button onClick={()=>this.setOperator('-')} className="btn-1">-</button>
      </div>
      <div>
      <button onClick={()=>this.addDigit(7)} className="btn-1">7</button>
      <button onClick={()=>this.addDigit(8)} className="btn-1">8</button>
      <button onClick={()=>this.addDigit(9)} className="btn-1">9</button>
      <button onClick={()=>this.setOperator('+')} className="btn-1">+</button>
      </div>
      <div>
      <button onClick={()=>this.addDigit(4)} className="btn-1">4</button>
      <button onClick={()=>this.addDigit(5)} className="btn-1">5</button>
      <button onClick={()=>this.addDigit(6)} className="btn-1">6</button>
      <button onClick={()=>this.setOperator('+')} className="btn-1">+</button>
      </div>
      <div>
      <button onClick={()=>this.addDigit(1)} className="btn-1">1</button>
      <button onClick={()=>this.addDigit(2)} className="btn-1">2</button>
      <button onClick={()=>this.addDigit(3)} className="btn-1">3</button>
      <button onClick={this.solve} className="btn-1">E</button>
      </div>
      <div>
      <button onClick={()=>this.addDigit(0)} className="btn-1">0</button>
      <button onClick={()=>this.addDigit(0)} className="btn-1">0</button>
      <button onClick={()=>this.addDigit('.')} className="btn-1">.</button>
      <button onClick={this.solve} className="btn-1">E</button>
      </div>
      </div>
      </div>
      )
      }
      });

      ReactDOM.render(
      <Calculator />,
      document.getElementById('root1')
      );


      I used React, ReactDOM and Babel.







      object-oriented calculator react.js jsx babel.js






      share|improve this question















      share|improve this question













      share|improve this question




      share|improve this question








      edited Aug 16 '17 at 17:48









      200_success

      129k15152414




      129k15152414










      asked Aug 16 '17 at 14:43









      StaggStagg

      285




      285






















          1 Answer
          1






          active

          oldest

          votes


















          3














          Fully functional example :






          class Calculator extends React.Component {
          constructor(props) {
          super(props)

          this.state = {
          currentNumber: ''
          }
          }

          addChar = char => ev => {
          if (!(this.state.currentNumber || ' ').endsWith(' ') || !char.endsWith(' ')){
          this.setState(prevState => ({
          currentNumber: prevState.currentNumber + char
          }))
          }
          }

          solve = () => {
          this.setState({
          currentNumber: eval(this.state.currentNumber)
          })
          }

          clear = () => {
          this.setState({
          currentNumber: ''
          })
          }

          render() {
          const layout = [
          [
          { name: 'C', func: this.clear },
          { name: ' / ' },
          { name: ' * ' },
          { name: ' - ' },
          ],
          [
          { name: '7' },
          { name: '8' },
          { name: '9' },
          { name: ' + ' },
          ],
          [
          { name: '4' },
          { name: '5' },
          { name: '6' },
          { name: ' + ' },
          ],
          [
          { name: '1' },
          { name: '2' },
          { name: '3' },
          { name: 'E', func: this.solve },
          ],
          [
          { name: '0' },
          { name: '0'},
          { name: '.' },
          { name: 'E', func: this.solve },
          ]
          ]

          return (
          <div>
          <h1>This here Cal-Q-lator</h1>
          <div>
          <input value={this.state.currentNumber || '0'} />
          {layout.map((line, i) =>
          <div key={i}>
          {line.map((field, i2) => <button key={i2} onClick={field.func || this.addChar(field.name)} className="btn-1">{field.name.trim()}</button>)}
          </div>
          )}
          </div>
          </div>
          )
          }
          }

          ReactDOM.render(
          <Calculator />,
          document.getElementById('root')
          );

          <script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
          <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
          <div id='root'/>





          For this review I will be using a class extending React.Component.



          First, your initial data. By default your calculator will be showing a 0 in the input field. Since this value is simply going to be deleted once the user types anything into the calculator interface, I suggest setting the default value of your input into an empty string, and just showing a 0 on the render side when the string is empty :



          State:



          constructor(props) {
          super(props)

          this.state = {
          currentNumber: ''
          }
          }


          Clear function:



          clear = () => {
          this.setState({
          currentNumber: ''
          })
          }


          Render:



          <input value={this.state.currentNumber || '0'} />


          Next up, handling operators and values. Both operators and value will do the same thing, adding characters to your currentNumber, the only difference being that operators will add spaces and cannot be displayed next to each other or at the beginning of the input.



          When setting a state value depending on an older one, you should avoid using the raw this.state and use the callback version of setState, allowing you to get the previous state and avoid any unexpected behavior :



          addChar = char => ev => {
          if (!(this.state.currentNumber || ' ').endsWith(' ') || !char.endsWith(' ')){
          this.setState(prevState => ({
          currentNumber: prevState.currentNumber + char
          }))
          }
          }


          Finally, layout.



          Every single button is made out of the same node, with the same classname. This part of the code can be drastically reduced. First, let's make an array containing what differs between every button: what is shown, and the action it does when you click it:



          const layout = [
          [
          { name: 'C', func: this.clear },
          { name: ' / ' },
          { name: ' * ' },
          { name: ' - ' },
          ],
          [
          { name: '7' },
          { name: '8' },
          { name: '9' },
          { name: ' + ' },
          ],
          [
          { name: '4' },
          { name: '5' },
          { name: '6' },
          { name: ' + ' },
          ],
          [
          { name: '1' },
          { name: '2' },
          { name: '3' },
          { name: 'E', func: this.solve },
          ],
          [
          { name: '0' },
          { name: '0' },
          { name: '.' },
          { name: 'E', func: this.solve },
          ]
          ]


          By default, every button will call the addChar function we made earlier, allowing use to reduce the code even further and make an nested array of JSON objects containing mostly button names.



          We can now render it by mapping every element to make buttons:



          {layout.map((line, i) => 
          <div key={i}>
          {line.map((field, i2) => <button key={i2} onClick={field.func || this.addChar(field.name)} className="btn-1">{field.name.trim()}</button>)}
          </div>
          )}


          Yes, I know this question is from 2017






          share|improve this answer


























          • I've worked with React after I posted this question for more then a year, I have to say it's nice to see my old code and how I've improved. Still, this gave some more ideas to optimise my logic in the future, Thanks for taking the time to answer this question :)

            – Stagg
            18 hours ago











          • You're welcome, glad it helped a year after posting it :)

            – Treycos
            17 hours ago











          Your Answer





          StackExchange.ifUsing("editor", function () {
          return StackExchange.using("mathjaxEditing", function () {
          StackExchange.MarkdownEditor.creationCallbacks.add(function (editor, postfix) {
          StackExchange.mathjaxEditing.prepareWmdForMathJax(editor, postfix, [["\$", "\$"]]);
          });
          });
          }, "mathjax-editing");

          StackExchange.ifUsing("editor", function () {
          StackExchange.using("externalEditor", function () {
          StackExchange.using("snippets", function () {
          StackExchange.snippets.init();
          });
          });
          }, "code-snippets");

          StackExchange.ready(function() {
          var channelOptions = {
          tags: "".split(" "),
          id: "196"
          };
          initTagRenderer("".split(" "), "".split(" "), channelOptions);

          StackExchange.using("externalEditor", function() {
          // Have to fire editor after snippets, if snippets enabled
          if (StackExchange.settings.snippets.snippetsEnabled) {
          StackExchange.using("snippets", function() {
          createEditor();
          });
          }
          else {
          createEditor();
          }
          });

          function createEditor() {
          StackExchange.prepareEditor({
          heartbeatType: 'answer',
          autoActivateHeartbeat: false,
          convertImagesToLinks: false,
          noModals: true,
          showLowRepImageUploadWarning: true,
          reputationToPostImages: null,
          bindNavPrevention: true,
          postfix: "",
          imageUploader: {
          brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
          contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
          allowUrls: true
          },
          onDemand: true,
          discardSelector: ".discard-answer"
          ,immediatelyShowMarkdownHelp:true
          });


          }
          });














          draft saved

          draft discarded


















          StackExchange.ready(
          function () {
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f173160%2freact-calculator%23new-answer', 'question_page');
          }
          );

          Post as a guest















          Required, but never shown

























          1 Answer
          1






          active

          oldest

          votes








          1 Answer
          1






          active

          oldest

          votes









          active

          oldest

          votes






          active

          oldest

          votes









          3














          Fully functional example :






          class Calculator extends React.Component {
          constructor(props) {
          super(props)

          this.state = {
          currentNumber: ''
          }
          }

          addChar = char => ev => {
          if (!(this.state.currentNumber || ' ').endsWith(' ') || !char.endsWith(' ')){
          this.setState(prevState => ({
          currentNumber: prevState.currentNumber + char
          }))
          }
          }

          solve = () => {
          this.setState({
          currentNumber: eval(this.state.currentNumber)
          })
          }

          clear = () => {
          this.setState({
          currentNumber: ''
          })
          }

          render() {
          const layout = [
          [
          { name: 'C', func: this.clear },
          { name: ' / ' },
          { name: ' * ' },
          { name: ' - ' },
          ],
          [
          { name: '7' },
          { name: '8' },
          { name: '9' },
          { name: ' + ' },
          ],
          [
          { name: '4' },
          { name: '5' },
          { name: '6' },
          { name: ' + ' },
          ],
          [
          { name: '1' },
          { name: '2' },
          { name: '3' },
          { name: 'E', func: this.solve },
          ],
          [
          { name: '0' },
          { name: '0'},
          { name: '.' },
          { name: 'E', func: this.solve },
          ]
          ]

          return (
          <div>
          <h1>This here Cal-Q-lator</h1>
          <div>
          <input value={this.state.currentNumber || '0'} />
          {layout.map((line, i) =>
          <div key={i}>
          {line.map((field, i2) => <button key={i2} onClick={field.func || this.addChar(field.name)} className="btn-1">{field.name.trim()}</button>)}
          </div>
          )}
          </div>
          </div>
          )
          }
          }

          ReactDOM.render(
          <Calculator />,
          document.getElementById('root')
          );

          <script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
          <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
          <div id='root'/>





          For this review I will be using a class extending React.Component.



          First, your initial data. By default your calculator will be showing a 0 in the input field. Since this value is simply going to be deleted once the user types anything into the calculator interface, I suggest setting the default value of your input into an empty string, and just showing a 0 on the render side when the string is empty :



          State:



          constructor(props) {
          super(props)

          this.state = {
          currentNumber: ''
          }
          }


          Clear function:



          clear = () => {
          this.setState({
          currentNumber: ''
          })
          }


          Render:



          <input value={this.state.currentNumber || '0'} />


          Next up, handling operators and values. Both operators and value will do the same thing, adding characters to your currentNumber, the only difference being that operators will add spaces and cannot be displayed next to each other or at the beginning of the input.



          When setting a state value depending on an older one, you should avoid using the raw this.state and use the callback version of setState, allowing you to get the previous state and avoid any unexpected behavior :



          addChar = char => ev => {
          if (!(this.state.currentNumber || ' ').endsWith(' ') || !char.endsWith(' ')){
          this.setState(prevState => ({
          currentNumber: prevState.currentNumber + char
          }))
          }
          }


          Finally, layout.



          Every single button is made out of the same node, with the same classname. This part of the code can be drastically reduced. First, let's make an array containing what differs between every button: what is shown, and the action it does when you click it:



          const layout = [
          [
          { name: 'C', func: this.clear },
          { name: ' / ' },
          { name: ' * ' },
          { name: ' - ' },
          ],
          [
          { name: '7' },
          { name: '8' },
          { name: '9' },
          { name: ' + ' },
          ],
          [
          { name: '4' },
          { name: '5' },
          { name: '6' },
          { name: ' + ' },
          ],
          [
          { name: '1' },
          { name: '2' },
          { name: '3' },
          { name: 'E', func: this.solve },
          ],
          [
          { name: '0' },
          { name: '0' },
          { name: '.' },
          { name: 'E', func: this.solve },
          ]
          ]


          By default, every button will call the addChar function we made earlier, allowing use to reduce the code even further and make an nested array of JSON objects containing mostly button names.



          We can now render it by mapping every element to make buttons:



          {layout.map((line, i) => 
          <div key={i}>
          {line.map((field, i2) => <button key={i2} onClick={field.func || this.addChar(field.name)} className="btn-1">{field.name.trim()}</button>)}
          </div>
          )}


          Yes, I know this question is from 2017






          share|improve this answer


























          • I've worked with React after I posted this question for more then a year, I have to say it's nice to see my old code and how I've improved. Still, this gave some more ideas to optimise my logic in the future, Thanks for taking the time to answer this question :)

            – Stagg
            18 hours ago











          • You're welcome, glad it helped a year after posting it :)

            – Treycos
            17 hours ago
















          3














          Fully functional example :






          class Calculator extends React.Component {
          constructor(props) {
          super(props)

          this.state = {
          currentNumber: ''
          }
          }

          addChar = char => ev => {
          if (!(this.state.currentNumber || ' ').endsWith(' ') || !char.endsWith(' ')){
          this.setState(prevState => ({
          currentNumber: prevState.currentNumber + char
          }))
          }
          }

          solve = () => {
          this.setState({
          currentNumber: eval(this.state.currentNumber)
          })
          }

          clear = () => {
          this.setState({
          currentNumber: ''
          })
          }

          render() {
          const layout = [
          [
          { name: 'C', func: this.clear },
          { name: ' / ' },
          { name: ' * ' },
          { name: ' - ' },
          ],
          [
          { name: '7' },
          { name: '8' },
          { name: '9' },
          { name: ' + ' },
          ],
          [
          { name: '4' },
          { name: '5' },
          { name: '6' },
          { name: ' + ' },
          ],
          [
          { name: '1' },
          { name: '2' },
          { name: '3' },
          { name: 'E', func: this.solve },
          ],
          [
          { name: '0' },
          { name: '0'},
          { name: '.' },
          { name: 'E', func: this.solve },
          ]
          ]

          return (
          <div>
          <h1>This here Cal-Q-lator</h1>
          <div>
          <input value={this.state.currentNumber || '0'} />
          {layout.map((line, i) =>
          <div key={i}>
          {line.map((field, i2) => <button key={i2} onClick={field.func || this.addChar(field.name)} className="btn-1">{field.name.trim()}</button>)}
          </div>
          )}
          </div>
          </div>
          )
          }
          }

          ReactDOM.render(
          <Calculator />,
          document.getElementById('root')
          );

          <script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
          <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
          <div id='root'/>





          For this review I will be using a class extending React.Component.



          First, your initial data. By default your calculator will be showing a 0 in the input field. Since this value is simply going to be deleted once the user types anything into the calculator interface, I suggest setting the default value of your input into an empty string, and just showing a 0 on the render side when the string is empty :



          State:



          constructor(props) {
          super(props)

          this.state = {
          currentNumber: ''
          }
          }


          Clear function:



          clear = () => {
          this.setState({
          currentNumber: ''
          })
          }


          Render:



          <input value={this.state.currentNumber || '0'} />


          Next up, handling operators and values. Both operators and value will do the same thing, adding characters to your currentNumber, the only difference being that operators will add spaces and cannot be displayed next to each other or at the beginning of the input.



          When setting a state value depending on an older one, you should avoid using the raw this.state and use the callback version of setState, allowing you to get the previous state and avoid any unexpected behavior :



          addChar = char => ev => {
          if (!(this.state.currentNumber || ' ').endsWith(' ') || !char.endsWith(' ')){
          this.setState(prevState => ({
          currentNumber: prevState.currentNumber + char
          }))
          }
          }


          Finally, layout.



          Every single button is made out of the same node, with the same classname. This part of the code can be drastically reduced. First, let's make an array containing what differs between every button: what is shown, and the action it does when you click it:



          const layout = [
          [
          { name: 'C', func: this.clear },
          { name: ' / ' },
          { name: ' * ' },
          { name: ' - ' },
          ],
          [
          { name: '7' },
          { name: '8' },
          { name: '9' },
          { name: ' + ' },
          ],
          [
          { name: '4' },
          { name: '5' },
          { name: '6' },
          { name: ' + ' },
          ],
          [
          { name: '1' },
          { name: '2' },
          { name: '3' },
          { name: 'E', func: this.solve },
          ],
          [
          { name: '0' },
          { name: '0' },
          { name: '.' },
          { name: 'E', func: this.solve },
          ]
          ]


          By default, every button will call the addChar function we made earlier, allowing use to reduce the code even further and make an nested array of JSON objects containing mostly button names.



          We can now render it by mapping every element to make buttons:



          {layout.map((line, i) => 
          <div key={i}>
          {line.map((field, i2) => <button key={i2} onClick={field.func || this.addChar(field.name)} className="btn-1">{field.name.trim()}</button>)}
          </div>
          )}


          Yes, I know this question is from 2017






          share|improve this answer


























          • I've worked with React after I posted this question for more then a year, I have to say it's nice to see my old code and how I've improved. Still, this gave some more ideas to optimise my logic in the future, Thanks for taking the time to answer this question :)

            – Stagg
            18 hours ago











          • You're welcome, glad it helped a year after posting it :)

            – Treycos
            17 hours ago














          3












          3








          3







          Fully functional example :






          class Calculator extends React.Component {
          constructor(props) {
          super(props)

          this.state = {
          currentNumber: ''
          }
          }

          addChar = char => ev => {
          if (!(this.state.currentNumber || ' ').endsWith(' ') || !char.endsWith(' ')){
          this.setState(prevState => ({
          currentNumber: prevState.currentNumber + char
          }))
          }
          }

          solve = () => {
          this.setState({
          currentNumber: eval(this.state.currentNumber)
          })
          }

          clear = () => {
          this.setState({
          currentNumber: ''
          })
          }

          render() {
          const layout = [
          [
          { name: 'C', func: this.clear },
          { name: ' / ' },
          { name: ' * ' },
          { name: ' - ' },
          ],
          [
          { name: '7' },
          { name: '8' },
          { name: '9' },
          { name: ' + ' },
          ],
          [
          { name: '4' },
          { name: '5' },
          { name: '6' },
          { name: ' + ' },
          ],
          [
          { name: '1' },
          { name: '2' },
          { name: '3' },
          { name: 'E', func: this.solve },
          ],
          [
          { name: '0' },
          { name: '0'},
          { name: '.' },
          { name: 'E', func: this.solve },
          ]
          ]

          return (
          <div>
          <h1>This here Cal-Q-lator</h1>
          <div>
          <input value={this.state.currentNumber || '0'} />
          {layout.map((line, i) =>
          <div key={i}>
          {line.map((field, i2) => <button key={i2} onClick={field.func || this.addChar(field.name)} className="btn-1">{field.name.trim()}</button>)}
          </div>
          )}
          </div>
          </div>
          )
          }
          }

          ReactDOM.render(
          <Calculator />,
          document.getElementById('root')
          );

          <script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
          <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
          <div id='root'/>





          For this review I will be using a class extending React.Component.



          First, your initial data. By default your calculator will be showing a 0 in the input field. Since this value is simply going to be deleted once the user types anything into the calculator interface, I suggest setting the default value of your input into an empty string, and just showing a 0 on the render side when the string is empty :



          State:



          constructor(props) {
          super(props)

          this.state = {
          currentNumber: ''
          }
          }


          Clear function:



          clear = () => {
          this.setState({
          currentNumber: ''
          })
          }


          Render:



          <input value={this.state.currentNumber || '0'} />


          Next up, handling operators and values. Both operators and value will do the same thing, adding characters to your currentNumber, the only difference being that operators will add spaces and cannot be displayed next to each other or at the beginning of the input.



          When setting a state value depending on an older one, you should avoid using the raw this.state and use the callback version of setState, allowing you to get the previous state and avoid any unexpected behavior :



          addChar = char => ev => {
          if (!(this.state.currentNumber || ' ').endsWith(' ') || !char.endsWith(' ')){
          this.setState(prevState => ({
          currentNumber: prevState.currentNumber + char
          }))
          }
          }


          Finally, layout.



          Every single button is made out of the same node, with the same classname. This part of the code can be drastically reduced. First, let's make an array containing what differs between every button: what is shown, and the action it does when you click it:



          const layout = [
          [
          { name: 'C', func: this.clear },
          { name: ' / ' },
          { name: ' * ' },
          { name: ' - ' },
          ],
          [
          { name: '7' },
          { name: '8' },
          { name: '9' },
          { name: ' + ' },
          ],
          [
          { name: '4' },
          { name: '5' },
          { name: '6' },
          { name: ' + ' },
          ],
          [
          { name: '1' },
          { name: '2' },
          { name: '3' },
          { name: 'E', func: this.solve },
          ],
          [
          { name: '0' },
          { name: '0' },
          { name: '.' },
          { name: 'E', func: this.solve },
          ]
          ]


          By default, every button will call the addChar function we made earlier, allowing use to reduce the code even further and make an nested array of JSON objects containing mostly button names.



          We can now render it by mapping every element to make buttons:



          {layout.map((line, i) => 
          <div key={i}>
          {line.map((field, i2) => <button key={i2} onClick={field.func || this.addChar(field.name)} className="btn-1">{field.name.trim()}</button>)}
          </div>
          )}


          Yes, I know this question is from 2017






          share|improve this answer















          Fully functional example :






          class Calculator extends React.Component {
          constructor(props) {
          super(props)

          this.state = {
          currentNumber: ''
          }
          }

          addChar = char => ev => {
          if (!(this.state.currentNumber || ' ').endsWith(' ') || !char.endsWith(' ')){
          this.setState(prevState => ({
          currentNumber: prevState.currentNumber + char
          }))
          }
          }

          solve = () => {
          this.setState({
          currentNumber: eval(this.state.currentNumber)
          })
          }

          clear = () => {
          this.setState({
          currentNumber: ''
          })
          }

          render() {
          const layout = [
          [
          { name: 'C', func: this.clear },
          { name: ' / ' },
          { name: ' * ' },
          { name: ' - ' },
          ],
          [
          { name: '7' },
          { name: '8' },
          { name: '9' },
          { name: ' + ' },
          ],
          [
          { name: '4' },
          { name: '5' },
          { name: '6' },
          { name: ' + ' },
          ],
          [
          { name: '1' },
          { name: '2' },
          { name: '3' },
          { name: 'E', func: this.solve },
          ],
          [
          { name: '0' },
          { name: '0'},
          { name: '.' },
          { name: 'E', func: this.solve },
          ]
          ]

          return (
          <div>
          <h1>This here Cal-Q-lator</h1>
          <div>
          <input value={this.state.currentNumber || '0'} />
          {layout.map((line, i) =>
          <div key={i}>
          {line.map((field, i2) => <button key={i2} onClick={field.func || this.addChar(field.name)} className="btn-1">{field.name.trim()}</button>)}
          </div>
          )}
          </div>
          </div>
          )
          }
          }

          ReactDOM.render(
          <Calculator />,
          document.getElementById('root')
          );

          <script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
          <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
          <div id='root'/>





          For this review I will be using a class extending React.Component.



          First, your initial data. By default your calculator will be showing a 0 in the input field. Since this value is simply going to be deleted once the user types anything into the calculator interface, I suggest setting the default value of your input into an empty string, and just showing a 0 on the render side when the string is empty :



          State:



          constructor(props) {
          super(props)

          this.state = {
          currentNumber: ''
          }
          }


          Clear function:



          clear = () => {
          this.setState({
          currentNumber: ''
          })
          }


          Render:



          <input value={this.state.currentNumber || '0'} />


          Next up, handling operators and values. Both operators and value will do the same thing, adding characters to your currentNumber, the only difference being that operators will add spaces and cannot be displayed next to each other or at the beginning of the input.



          When setting a state value depending on an older one, you should avoid using the raw this.state and use the callback version of setState, allowing you to get the previous state and avoid any unexpected behavior :



          addChar = char => ev => {
          if (!(this.state.currentNumber || ' ').endsWith(' ') || !char.endsWith(' ')){
          this.setState(prevState => ({
          currentNumber: prevState.currentNumber + char
          }))
          }
          }


          Finally, layout.



          Every single button is made out of the same node, with the same classname. This part of the code can be drastically reduced. First, let's make an array containing what differs between every button: what is shown, and the action it does when you click it:



          const layout = [
          [
          { name: 'C', func: this.clear },
          { name: ' / ' },
          { name: ' * ' },
          { name: ' - ' },
          ],
          [
          { name: '7' },
          { name: '8' },
          { name: '9' },
          { name: ' + ' },
          ],
          [
          { name: '4' },
          { name: '5' },
          { name: '6' },
          { name: ' + ' },
          ],
          [
          { name: '1' },
          { name: '2' },
          { name: '3' },
          { name: 'E', func: this.solve },
          ],
          [
          { name: '0' },
          { name: '0' },
          { name: '.' },
          { name: 'E', func: this.solve },
          ]
          ]


          By default, every button will call the addChar function we made earlier, allowing use to reduce the code even further and make an nested array of JSON objects containing mostly button names.



          We can now render it by mapping every element to make buttons:



          {layout.map((line, i) => 
          <div key={i}>
          {line.map((field, i2) => <button key={i2} onClick={field.func || this.addChar(field.name)} className="btn-1">{field.name.trim()}</button>)}
          </div>
          )}


          Yes, I know this question is from 2017






          class Calculator extends React.Component {
          constructor(props) {
          super(props)

          this.state = {
          currentNumber: ''
          }
          }

          addChar = char => ev => {
          if (!(this.state.currentNumber || ' ').endsWith(' ') || !char.endsWith(' ')){
          this.setState(prevState => ({
          currentNumber: prevState.currentNumber + char
          }))
          }
          }

          solve = () => {
          this.setState({
          currentNumber: eval(this.state.currentNumber)
          })
          }

          clear = () => {
          this.setState({
          currentNumber: ''
          })
          }

          render() {
          const layout = [
          [
          { name: 'C', func: this.clear },
          { name: ' / ' },
          { name: ' * ' },
          { name: ' - ' },
          ],
          [
          { name: '7' },
          { name: '8' },
          { name: '9' },
          { name: ' + ' },
          ],
          [
          { name: '4' },
          { name: '5' },
          { name: '6' },
          { name: ' + ' },
          ],
          [
          { name: '1' },
          { name: '2' },
          { name: '3' },
          { name: 'E', func: this.solve },
          ],
          [
          { name: '0' },
          { name: '0'},
          { name: '.' },
          { name: 'E', func: this.solve },
          ]
          ]

          return (
          <div>
          <h1>This here Cal-Q-lator</h1>
          <div>
          <input value={this.state.currentNumber || '0'} />
          {layout.map((line, i) =>
          <div key={i}>
          {line.map((field, i2) => <button key={i2} onClick={field.func || this.addChar(field.name)} className="btn-1">{field.name.trim()}</button>)}
          </div>
          )}
          </div>
          </div>
          )
          }
          }

          ReactDOM.render(
          <Calculator />,
          document.getElementById('root')
          );

          <script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
          <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
          <div id='root'/>





          class Calculator extends React.Component {
          constructor(props) {
          super(props)

          this.state = {
          currentNumber: ''
          }
          }

          addChar = char => ev => {
          if (!(this.state.currentNumber || ' ').endsWith(' ') || !char.endsWith(' ')){
          this.setState(prevState => ({
          currentNumber: prevState.currentNumber + char
          }))
          }
          }

          solve = () => {
          this.setState({
          currentNumber: eval(this.state.currentNumber)
          })
          }

          clear = () => {
          this.setState({
          currentNumber: ''
          })
          }

          render() {
          const layout = [
          [
          { name: 'C', func: this.clear },
          { name: ' / ' },
          { name: ' * ' },
          { name: ' - ' },
          ],
          [
          { name: '7' },
          { name: '8' },
          { name: '9' },
          { name: ' + ' },
          ],
          [
          { name: '4' },
          { name: '5' },
          { name: '6' },
          { name: ' + ' },
          ],
          [
          { name: '1' },
          { name: '2' },
          { name: '3' },
          { name: 'E', func: this.solve },
          ],
          [
          { name: '0' },
          { name: '0'},
          { name: '.' },
          { name: 'E', func: this.solve },
          ]
          ]

          return (
          <div>
          <h1>This here Cal-Q-lator</h1>
          <div>
          <input value={this.state.currentNumber || '0'} />
          {layout.map((line, i) =>
          <div key={i}>
          {line.map((field, i2) => <button key={i2} onClick={field.func || this.addChar(field.name)} className="btn-1">{field.name.trim()}</button>)}
          </div>
          )}
          </div>
          </div>
          )
          }
          }

          ReactDOM.render(
          <Calculator />,
          document.getElementById('root')
          );

          <script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
          <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
          <div id='root'/>






          share|improve this answer














          share|improve this answer



          share|improve this answer








          edited yesterday









          Toby Speight

          23.5k639112




          23.5k639112










          answered 2 days ago









          TreycosTreycos

          23518




          23518













          • I've worked with React after I posted this question for more then a year, I have to say it's nice to see my old code and how I've improved. Still, this gave some more ideas to optimise my logic in the future, Thanks for taking the time to answer this question :)

            – Stagg
            18 hours ago











          • You're welcome, glad it helped a year after posting it :)

            – Treycos
            17 hours ago



















          • I've worked with React after I posted this question for more then a year, I have to say it's nice to see my old code and how I've improved. Still, this gave some more ideas to optimise my logic in the future, Thanks for taking the time to answer this question :)

            – Stagg
            18 hours ago











          • You're welcome, glad it helped a year after posting it :)

            – Treycos
            17 hours ago

















          I've worked with React after I posted this question for more then a year, I have to say it's nice to see my old code and how I've improved. Still, this gave some more ideas to optimise my logic in the future, Thanks for taking the time to answer this question :)

          – Stagg
          18 hours ago





          I've worked with React after I posted this question for more then a year, I have to say it's nice to see my old code and how I've improved. Still, this gave some more ideas to optimise my logic in the future, Thanks for taking the time to answer this question :)

          – Stagg
          18 hours ago













          You're welcome, glad it helped a year after posting it :)

          – Treycos
          17 hours ago





          You're welcome, glad it helped a year after posting it :)

          – Treycos
          17 hours ago


















          draft saved

          draft discarded




















































          Thanks for contributing an answer to Code Review Stack Exchange!


          • Please be sure to answer the question. Provide details and share your research!

          But avoid



          • Asking for help, clarification, or responding to other answers.

          • Making statements based on opinion; back them up with references or personal experience.


          Use MathJax to format equations. MathJax reference.


          To learn more, see our tips on writing great answers.




          draft saved


          draft discarded














          StackExchange.ready(
          function () {
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f173160%2freact-calculator%23new-answer', 'question_page');
          }
          );

          Post as a guest















          Required, but never shown





















































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown

































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown







          Popular posts from this blog

          Сан-Квентин

          8-я гвардейская общевойсковая армия

          Алькесар