FrontEnd Developer Road Map

React Tutorial 2023 33 – Two-Way Binding Olayı

Merhabalar.

Bir yazımda React’te Two-Way Binding olayını inceleyeceğiz.

Bir önceki yazımdan hatırlayacağınız üzere Calculator uygulamamız vardı. Bu konuyu yine Calculator üzerinden sizlere anlatmaya çalışacağım.

Biz ekranda sayılar girip bir işlem yaptırdığımızda, onSubmit olayında preventDefault() kullandığımız için sayfa yenilenmez ve Inputbox’lara yazdığımız değerler aynen kalır. Ama bazı durumlarda biz bu değerler işlem sonrasında sıfırlansın isteriz. İşte bu işlemi yapmak için kullanacağımız yönteme Two-Way Binding yöntemi diyoruz.

Burada yapmamız gereken işlem şu.

Inputbox’ların value property’lerini dinamik yönetmek. Her Inputbox ve Dropdownbox için birer state değişkeni tanımlayacağız. Sonrasında bu input’ların onChange event’lerine değişim değerlerini set edeceğiz.

Tüm işlem bittiğinde bu değerlerin içini boşaltacağız. Böylece alanlar temizlenmiş olacak.

Kodlamaya geçebiliriz.

InputState’inin Eklenmesi

State olarak aşağıdaki kodu ekliyoruz.

const [inputState, setInputState] = useState({
        num1: 0,
        num2: 0,
        operation: '',
    });

InitialInputState Fonksiyonunun Yazılması

Bu değişkenleri başlangıç değerlerine set edecek bir initialInputState fonksiyonu yazıyorum.

Bu fonksiyon sayesinde Two-Way Binding işlemini gerçekleştireceğim.

const initialInputState = () => {

        setInputState(prevState => ({

            num1: 0,
            num2: 0,
            operation: '',
        }));
    }

UpdateInput Fonksiyonunun Yazılması

InputState’leri, input’lardaki değerlere göre güncelleyecek update fonksiyonunu yazalım.

const updateInputState = (event) => {

        const { name, value } = event.target;

        setInputState(prevState => ({
            ...prevState,
            [name]: value,
        }));
    }

Update işlemi gerçekleştirirken değerler bir input’tan geleceği için ve bu fonksiyon input’ların onChange event’ine bağlanacağı için, event parametresi ile elementin kendisini yakalayabiliyordum.

Sonra name, value değişkenlerini, destructuring yöntemiyle targettan çekiyorum.

Bu sayede şu gerçekleşiyor gelen input’un name’i “num1” key olarak name değişkenine gidiyor, value değeri de value’ya gidiyor.

Sonra yaptığımız işlem eski değerleri al ve sana gönderilen name ile bir key yarat ve değeri kendisine ata ve güncelle. Böylece her input için farklı fonksiyonlar yazmaktan kurtulmuş olduk.

Form Elemanlarını Güncelle

Şimdi form ögeleri üzerinde yaptığımız güncellemelere bakalım.

<form onSubmit={handleCalculate}>
                <input type="number" name="num1" value={inputState.num1} onChange={updateInputState} required />
                <input type="number" name="num2" value={inputState.num2} onChange={updateInputState} required />
                <select name="operation" value={inputState.operation} onChange={updateInputState} required>
                    <option value="">Select operation</option>
                    <option value="add">Add</option>
                    <option value="subtract">Subtract</option>
                    <option value="multiply">Multiply</option>
                    <option value="divide">Divide</option>
                </select>
                <button type="submit">Calculate</button>
            </form>

Input’lara value property’leri eklendi ve state’lerden güncellenecek şekilde ayarlandı.

onChange event’lerine update fonksiyonu bağlandı.

InitialInputState Fonksiyonunu Çalıştır – Two-Way Binding Gerçekleşsin

Artık son olarak Calculate işleminin sonunda initial fonksiyonunun çağrılması kaldı.

initialInputState();

İşte istediğimiz şeyi elde edebilmiş olduk.

Uygulama Testi

Şimdi testlerimize bakalım.

İki işlem gerçekleştirdim. İşlemlerim sonrasında input alanlarım sıfırlandı.

Son olarak kodların tamamını paylaşayım. İnceleyebilmeniz adına.

import "./Calculator.css";
import React, { useState } from 'react';

const Calculator = () => {

    // #region States

    const [inputState, setInputState] = useState({

        num1: 0,
        num2: 0,
        operation: '',
    });

    const [allState, setAllState] = useState({
        result: 0,
        count: 0,
        operationInfoOpen: false,
        alertMessage: '',
    });

    const [history, setHistory] = useState([]);

    // #endregion 

    // #region Functions

    const updateAlertMessage = (message) => {
        setAllState(prevState => ({
            ...prevState,
            alertMessage: message,
        }));
    }

    const updateResult = (result) => {

        setAllState(prevState => ({
            ...prevState,
            result: result,
            count: prevState.count + 1,
        }));

    }

    const updateOperationInfoOpen = (isOpen) => {

        setAllState(prevState => ({
            ...prevState,
            operationInfoOpen: isOpen,

        }));
    }

    const updateHistory = (operation, num1, num2, result) => {
        setHistory(prevList => [{ count: prevList.length + 1, operation, num1, num2, result }, ...prevList]);
    }

    const updateInputState = (event) => {

        const { name, value } = event.target;

        setInputState(prevState => ({
            ...prevState,
            [name]: value,
        }));
    }

    const initialInputState = () => {

        setInputState(prevState => ({

            num1: 0,
            num2: 0,
            operation: '',
        }));
    }

    const handleToggleOperationInfo = () => {

        if (history.length !== 0) {

            updateOperationInfoOpen(!allState.operationInfoOpen);
        }
        else {

            updateAlertMessage('There is no operation history');
            setTimeout(() => updateAlertMessage(''), 5000);
        }
    };

    const handleCalculate = (event) => {

        event.preventDefault();

        const form = event.target;
        const num1 = parseFloat(form.elements.num1.value);
        const num2 = parseFloat(form.elements.num2.value);
        const operation = form.elements.operation.value;

        let result;

        switch (operation) {
            case 'add':
                result = num1 + num2;
                updateHistory('+', num1, num2, result);
                break;
            case 'subtract':
                result = num1 - num2;
                updateHistory('-', num1, num2, result);
                break;
            case 'multiply':
                result = num1 * num2;
                updateHistory('*', num1, num2, result);
                break;
            case 'divide':
                if (num2 !== 0) {
                    result = num1 / num2;
                    updateHistory('/', num1, num2, result);
                } else {
                    updateAlertMessage('Cannot divide by zero');
                    setTimeout(() => updateAlertMessage(''), 5000);

                }
                break;
            default:
                updateAlertMessage('Invalid operation');
                setTimeout(() => updateAlertMessage(''), 5000);
        }

        updateResult(result);
        initialInputState();
    };

    // #endregion

    // #region Render

    return (

        <div className="app">

            {allState.alertMessage ?

                <div className="header">
                    <div className="alert">{allState.alertMessage}</div>
                </div> : null

            }

            <div className={`operation-info info-container ${allState.operationInfoOpen ? 'open' : ''}`}>
                <h4>Operation History</h4>
                {history.map((process, index) => (
                    <p key={index}>{process.count}: {process.num1} {process.operation} {process.num2} = {process.result}</p>
                ))}
            </div>

            <div className="toggle-container">

                <span className="mr">{allState.operationInfoOpen ? 'Close' : 'Open'} History</span>
                <button className={`toggle-button ${allState.operationInfoOpen ? 'active' : ''}`} onClick={handleToggleOperationInfo}>

                </button>

            </div>

            <div className="result">
                <h1 id="result">{allState.result}</h1>
                <span>İşlem Adeti: {allState.count}</span>
            </div>

            <form onSubmit={handleCalculate}>
                <input type="number" name="num1" value={inputState.num1} onChange={updateInputState} required />
                <input type="number" name="num2" value={inputState.num2} onChange={updateInputState} required />
                <select name="operation" value={inputState.operation} onChange={updateInputState} required>
                    <option value="">Select operation</option>
                    <option value="add">Add</option>
                    <option value="subtract">Subtract</option>
                    <option value="multiply">Multiply</option>
                    <option value="divide">Divide</option>
                </select>
                <button type="submit">Calculate</button>
            </form>

        </div>


    )

    // #endregion
}

export default Calculator;

Bu olaya two-way binding diyorduk örneğiyle öğrenmiş olduk.

Bir sonraki yazımda görüşmek üzere.

Murat Bilginer

21 Şubat 1992'de doğdum. Endüstri Mühendisi olarak lisansımı 2016 yılında tamamladım. Industryolog Akademi - NGenius oluşumlarının kurucusuyum. Şu anda kendi şirketim Brainy Tech ile Web ve Mobil Geliştirme, AWS, Google Cloud Platform Sistemleri için DevOps, Big Data Analiz ve Görselleştirme hizmetleri sunmakta ve Online Eğitimler vermekteyiz.

Share
Published by
Murat Bilginer

Recent Posts

Kedimiz Oly & FIP Süreci 9 – 1 Haftalık GS İğnesi Serüveni – Oly İyileşiyor mu?

Selamlar, bu yazımda Oly'nin 1 hafta boyunca olduğu GS iğnesi, yaşanan değişimleri anlatmaya çalışacağım. PCR…

2 gün ago

Kedimiz Oly & FIP Süreci 8 – Yeniden Hayvan Hastanesi – Sonuç Kontrolü ve Sonrası…

Selamlar, bu yazımda Hemogram ve Biyokimya sonuçlarımızı göstermek için İÜCHH'ne tekrar gidişimizi ve sonrasını anlatacağım.…

2 gün ago

Kedimiz Oly & FIP Süreci 7 – GS İğnesine Başlama Kararımız ve Oly’de Dikkat Ettiklerimiz

Selamlar, bu yazımda GS iğnesine başlama kararımızı ve Oly’de bu süreçte nelere dikkat ediyor, neler…

2 gün ago

Kedimiz Oly & FIP Süreci 6 – İstanbul Üniversitesi Cerrahpaşa Hayvan Hastanesi Serüveni ve Sonrası

Selamlar, bu yazımda İÜCHH'deki tedavi sürecimiz ve sonrasında yaşananlardan bahsetmeye çalışacağım. 20.06.2025 Cuma günü saat…

3 gün ago

Kedimiz Oly & FIP Süreci 5 – Teşhisten Önce Biz… Veterinerimize Güvenebilir Miydik?

Eve Dönüş ve İlk Şüpheler 18 Haziran Perşembe saat 23 sularında İstanbul’daki evimize giriş yaptık.…

4 gün ago

Kedimiz Oly & FIP Süreci 4 – Antalya’ya Yolculuk – Bir Şeyler Ters Gidiyor… & İstanbul’a Geri Dönüş

9 Haziran Pazartesi günü Aydın’daki sürecimiz bitti ve Antalya yolculuğumuz başladı. Saat 11 gibi yola…

4 gün ago