State Güncellemek
Çoğu zaman, birden çok componentin aynı state’i yansıtması gerekir. Bu bölümde, suyun belirli bir sıcaklıkta kaynayıp kaynayamayacağını hesaplayan fonksiyonları oluşturacağız.
BoilingVerdict
adlı bir componentle başlayacağız. Celsius
sıcaklığını bir props ile parametre olarak kabul eder ve suyu kaynatmaya yetecek kadar olup olmadığını return eder:
function BoilingVerdict(props) {
if (props.celsius >= 100) {
return <p>Su kaynar.</p>;
}
return <p>Suyun kaynaması için yeterli sıcaklık değil.</p>;
}
Sonra, Calculator
adlı bir component oluşturacağız.
Sıcaklığı girmenizi sağlayıp, bu değeri this.state.temperature
‘te tutacak:
class Calculator extends React.Component {
constructor(props) {
super(props);
this.handleChange = this.handleChange.bind(this);
this.state = {temperature: ''};
}
handleChange(e) {
this.setState({temperature: e.target.value});
}
render() {
const temperature = this.state.temperature;
return (
<fieldset>
<legend>Celsius sıcaklığını giriniz:</legend>
<input value={temperature} onChange={this.handleChange} />
<BoilingVerdict celsius={parseFloat(temperature)} />
</fieldset>
);
}
}
İkinci Inputu Eklemek
Şimdi yapacağımız şey ise Celsius inputuna ek olarak, bir Fahrenheit inputu sağlamak.
TemperatureInput
componentinden devam edebiliriz.
Yeni bir scale
propsu ekleyeceğiz ki bunlar c
ya da f
olabilirler:
const scaleNames = {
c: 'Celsius',
f: 'Fahrenheit'
};
class TemperatureInput extends React.Component {
constructor(props) {
super(props);
this.handleChange = this.handleChange.bind(this);
this.state = {temperature: ''};
}
handleChange(e) {
this.setState({temperature: e.target.value});
}
render() {
const temperature = this.state.temperature;
const scale = this.props.scale;
return (
<fieldset>
<legend>{scaleNames[scale]} sıcaklığını giriniz:</legend>
<input value={temperature} onChange={this.handleChange} />
</fieldset>
);
}
}
Artık iki ayrı sıcaklık girişi oluşturmak için Calculator
componentini şu şekilde değiştirebiliriz:
class Calculator extends React.Component {
render() {
return (
<div>
<TemperatureInput scale="c" />
<TemperatureInput scale="f" />
</div>
);
}
}
Şu anda iki inputumuz var, ancak sıcaklıkların birine rakam yazdığımızda diğeri güncellenmiyor. Bu bizim gereksinimimizle çelişiyor, onları senkronize etmeyi istiyoruz.
Dönüştürme Fonksiyonları
İlk olarak Celsius ve Fahrenheit’ı birbirine dönüştürmek için gerekli iki fonksiyonu yazacağız:
function toCelsius(fahrenheit) {
return (fahrenheit - 32) * 5 / 9;
}
function toFahrenheit(celsius) {
return (celsius * 9 / 5) + 32;
}
Bu iki fonksiyon, sıcaklıkları birbirine dönüştürür.
State Güncellemek
Şu anda, TemperatureInput
componenti bağımsız olarak değerlerini local state’te tutuyor:
class TemperatureInput extends React.Component {
constructor(props) {
super(props);
this.handleChange = this.handleChange.bind(this);
this.state = {temperature: ''};
}
handleChange(e) {
this.setState({temperature: e.target.value});
}
render() {
const temperature = this.state.temperature;
// ...
Bununla birlikte, bu iki inputun birbiriyle senkronize edilmesini istiyoruz. Celsius inputu güncellendiğinde, Fahrenheit inputu dönüştürülen sıcaklığı göstermelidir; aynı zamanda tersi de çalışmalıdır.
React’ta state, ihtiyaç duyan componentlerin en yakın ortak atasına taşınarak gerçekleştirilir.
Bunun yerine, state’i TemperatureInput
den çıkaracak ve onu Calculator
içine taşıyacağız.
Bunun nasıl olduğunu adım adım işleyelim.
İlk olarak, TemperatureInput
componentinde this.state.temperature
öğesini this.props.temperature
olarak değiştirelim.
render() {
// Önceden: const temperature = this.state.temperature;
const temperature = this.props.temperature;
// ...
Propsların read-only (sadece okunabilir, değiştirilemez) olduğunu biliyoruz.
temperature
state’teyken, TemperatureInput
bunu değiştirmek için this.setState()
yi çağırabilir.
Şimdi, TemperatureInput
sıcaklığı güncellemek istediğinde, this.props.onTemperatureChange
fonksiyonu yardımı ile yapacak:
handleChange(e) {
// Önceden: this.setState({temperature: e.target.value});
this.props.onTemperatureChange(e.target.value);
// ...
Not:
temperature
veyaonTemperatureChange
adlarının özel bir anlamı yoktur. Onlara,value
veonChange
gibi isimler verdik, başka bir şey diyebilirdik.
class TemperatureInput extends React.Component {
constructor(props) {
super(props);
this.handleChange = this.handleChange.bind(this);
}
handleChange(e) {
this.props.onTemperatureChange(e.target.value);
}
render() {
const temperature = this.props.temperature;
const scale = this.props.scale;
return (
<fieldset>
<legend>{scaleNames[scale]} sıcaklığını giriniz:</legend>
<input value={temperature}
onChange={this.handleChange} />
</fieldset>
);
}
}
Şimdi Calculator
componentine geçelim.
Mevcut inputun temperature
ve scale
değerlerini statede tutarız.
Örneğin, Celsius’a 37 yazarsak, Calculator
componentinin state’i şöyle olacaktır:
{
temperature: '37',
scale: 'c'
}
Eğer daha sonra Fahrenheit’ı 212 olarak değişirsek Calculator
componenti şöyle olur:
{
temperature: '212',
scale: 'f'
}
Her ikisinin girdisinide tutabilirdik fakat gereksiz olurdu.
En son girilen girdinin değerini ve gösterdiği ölçeği tutmak yeterlidir.
Daha sonra temperature
ve scale
değerlerine bağlı olarak diğerinin değerini hesaplayabiliriz.
class Calculator extends React.Component {
constructor(props) {
super(props);
this.handleCelsiusChange = this.handleCelsiusChange.bind(this);
this.handleFahrenheitChange = this.handleFahrenheitChange.bind(this);
this.state = {temperature: '', scale: 'c'};
}
handleCelsiusChange(temperature) {
this.setState({scale: 'c', temperature});
}
handleFahrenheitChange(temperature) {
this.setState({scale: 'f', temperature});
}
render() {
const scale = this.state.scale;
const temperature = this.state.temperature;
const celsius = scale === 'f' ? tryConvert(temperature, toCelsius) : temperature;
const fahrenheit = scale === 'c' ? tryConvert(temperature, toFahrenheit) : temperature;
return (
<div>
<TemperatureInput
scale="c"
temperature={celsius}
onTemperatureChange={this.handleCelsiusChange} />
<TemperatureInput
scale="f"
temperature={fahrenheit}
onTemperatureChange={this.handleFahrenheitChange} />
<BoilingVerdict
celsius={parseFloat(celsius)} />
</div>
);
}
}
Şu anda, hangi inputun düzenlediğiniz önemli değil, Calculator’daki this.state.temperature
ve this.state.scale
güncellenir. Inputlardan bir tanesi olduğu gibi değeri alır, diğer input değeri daima buna dayalı olarak yeniden hesaplanır.