Get up to 80 % extra points for free! More info:

Lesson 3 - React calculator components

In the last lesson, First application in React, we started creating a simple calculator using the React library.

Today we will add properties and states to the calculator component.

Components

We begin concept properties that are used for configuration and data transfer into components.

Properties

We simply write an attribute to the component within JSX, eg x="5", and this component will then make it available internally via props, ie props.x. In short, it will be 5. Let's take an example.

src/calculator/Result.js

The use of a property (props) is beautifully suited for our result display component. As a parameter, we pass the current value to be displayed:

import React from 'react';

const Result = (props) => {
    const result = props.value;
    if (result || result === 0)
        return <div className="Result">Result: {result}</div>;
    else return null;
};

export default Result;

There are several things that happen in this code. We pass the value of the displayed result using the value property and store it in the local result constant. We then work with it and, according to its value, check whether we should display our result or not.

It's a good idea to point out that if a component has nothing to render, it should return null. It follows from the functional paradigm - a function must always return a value.

Next, we can try to use the property. Simply set inside the CalculatorForm component, for example: <Result value="5" /> and we should immediately see the result in the running application:)

src/calculator/NumberInput.js

Before we illustrate how states and events work, we will prepare the NumberInput component:

import React from 'react';

let NumberInput = (props) => {
    const { name, label } = props;
    return (
        <label htmlFor={name}>
            {label}
            <input
                onChange={props.OnChange}
                id={name}
                type="number"
                name={name}
                required
            />
        </label>
    );
};

export default NumberInput;

As we can see, we added the properties of the name and label components, but we have to pass them in the parameters of the function (they are always called props). It is smarter to see that we have also prepared an onChange event, which we will also pass to the properties of the component and we will work with it in another component.

And now to the states and the processing of events.

State

State (state) is similar characteristics, but is only used inside the components for control of data flow. In essence, this is the component's private data for internal use only. Let's show it again with an example.

The React functional uses the useState library to manage states. In order to use useState(), we need to import this library. Set an empty string ("") or 0 as the initial value. Let's not be afraid that our IDE will underline setState and announce that we don't use it anywhere. We'll get to that:-)

src/calculator/CalculatorForm.js

We will create an array that will contain two variables - one is the initial state, the other will be stored later. setResult possible code, it is good to name these variables, for example here result and setResult or even better resultState and setResultState.

We pass the original state to the useState() function resultState variable. This can be an empty string useState(""), null or any value. We then change the value of the variable using setResultState, most often we do it when processing events (the value changes after the user clicks on something):

import React, { useState } from 'react';
import NumberInput from './NumberInput';
import Select from 'react-select';
import Result from './Result';

const CalculatorForm = (props) => {
    const [selectedOptionState, setSelectedOptionState] = useState({
        selectedOption: {
            value: '--Select operation--',
            label: '--Select operation--',
        },
    });
    const [resultState, setResultState] = useState(null);

    const options = [
        { value: 'ADD', label: 'Add' },
        { value: 'SUBTRACT', label: 'Subtract' },
        { value: 'MULTIPLY', label: 'Multiply' },
        { value: 'DIVIDE', label: 'Divide' },
    ];

    const handleSubmit = (event) => {
        event.preventDefault();
        //const result = calculate();
        //setResultState(result);
    };
    const handleChange = (selectedOptionState) => {
        setSelectedOptionState({ selectedOptionState });
    };
    return (
        <div>
            <form className="CalculatorForm" onSubmit={handleSubmit}>
                <NumberInput
                    OnChange={props.xOnChange}
                    name="x"
                    label="First number:"
                    value={props.x}
                />
                <NumberInput
                    OnChange={props.yOnChange}
                    name="y"
                    label="Second number:"
                    value={props.y}
                />
                <Select
                    onChange={handleChange}
                    value={selectedOptionState.value}
                    options={options}
                />
                <input value="Count" type="submit" />
            </form>
            <Result value={resultState} />
        </div>
    );
};

export default CalculatorForm;

We see that the handleChange() and handleSubmit() functions are used to store the new value of the variable and other actions that the application will perform after calling this function. In our case, it will later be the calculate() function, which will take care of the very essence of the calculator, ie the use of mathematical operations. So far, we have handleSubmit() function so that we can compile the calculator.

Great, we were able to synchronize our state with the value in the <input> element. Now, if we write something in it, the handleChange() method is called and the internal state of the component is updated. Note also that we have our own event for both numeric inputs, ie xOnChange and yOnChange.

Finally, here we promote our state to the outside world. As we have already explained, the state is only for our internal needs, so if we want to manifest it externally, we will arrange it by promoting it through properties. In our case, we are only promoting the event to our props.onChange property with a slight improvement in number conversion. So the one who will use our program will always get a numeric value (or NaN), as we would probably expect from a numerical input :)

So far we have an incomplete calculator which we will finish in the next lesson.

Result.js

import React, { Component } from 'react';

export default class Result extends Component {
    render() {
        const result = this.props.value;
        if (result || result === 0) return <div className="Result">Result: {result}</div>;
        else return null;
    }
}

NumberInput.js

import React, { Component } from 'react';

export default class NumberInput extends Component {
    constructor(props) {
        super(props);
        this.state = { value: this.props.value };
        this.handleChange = this.handleChange.bind(this);
    }

    handleChange(event) {
        const value = event.target.value;
        this.setState({ value });
        this.props.onChange(Number(value));
    }

    render() {
        const { name, label } = this.props;

        return (
            <label htmlFor={name}>
                {label}
                <input id={name} type="number" name={name} required
                    value={this.state.value}
                    onChange={this.handleChange} />
            </label>
        );
    }
}

CalculatorForm.js

export default class CalculatorForm extends Component {
    constructor(props) {
        super(props);
        this.state = { x: 0, y: 0, operation: null, result: null };

        const handleChange = (name, value) => this.setState({ [name]: value });
        this.handleChangeX = handleChange.bind(this, 'x');
        this.handleChangeY = handleChange.bind(this, 'y');
    }

    render() {
        return (
            <form className="CalculatorForm">
                <NumberInput name="x"
                             value={this.state.x}
                             onChange={this.handleChangeX} />
                <NumberInput name="y"
                             value={this.state.y}
                             onChange={this.handleChangeY} />
                <OperationSelect />
                <input type="submit" value="Count" />
            </form>
        );
    }
}

In the next lesson, Completing the React Calculator, we'll finish the calculator in React.


 

Previous article
First application in React
All articles in this section
React Basics
Skip article
(not recommended)
Completing the React Calculator
Article has been written for you by Vlasta
Avatar
User rating:
No one has rated this quite yet, be the first one!
Passionate reader, student, coder and writer.
Activities