20 Mart 2021 Cumartesi

React.forwarRef + React.useImperativeHandle kullanımı

  Ahmet Şimşek       20 Mart 2021 Cumartesi

forwarRef parent bir componentten child component ile ref paylaşabilmeyi sağlar.

Örnek bir kullanım hemen aşağıda. Counter componentini forwardRef ile sarmaladığımız durumda ilk parametre aldığı propslar ikincisi ise parent component ile gönderilen ref. Bu ref button ile paylaşılıyor ve üst component mount olduğu durumda butonun click event ını çağırdığımız için görünecek olan count değerini 1 arttırmış oluyoruz.

import React, { useState, useEffect } from "react";
import PropTypes from "prop-types";

const Counter = React.forwardRef(({ initialCount }, ref) => {
const [count, setCount] = useState(initialCount);

const handleIncrementClick = () => {
setCount((count) => count + 1);
};

return (
<div>
count: {count}
<button onClick={handleIncrementClick} ref={ref}>
+
</button>
</div>
);
});

Counter.propTypes = { initialCount: PropTypes.number.isRequired };

export default function App() {
const incrementButtonRef = React.useRef();

useEffect(() => {
if (incrementButtonRef.current) {
incrementButtonRef.current.click();
}
}, [incrementButtonRef]);

return (
<div className="App">
<Counter initialCount={10} ref={incrementButtonRef} />
</div>
);
}

Bu kullanım güzel ama tek bir element/component ile ref paylaşabileceğimiz için çok dinamik bir yapı ortaya çıkaramıyoruz. Örneğin ref ile increment ve decrement fonksiyonlarına erişebilsek nasıl olurdu? Bunu da useImperativeHandle ile gerçekleştirebiliriz.

Aşağıdaki kullanım ile parent üzerinden paylaştığımız ref ile child component içerisinde çağırabileceğimiz fonksiyonları useImperativeHandle ile paylaşabiliyoruz. increment ve decrement fonksiyonlarını parent componentten çağırdığımız durumda state değişimlerinin direkt yansıdığını görebiliriz.

import "./styles.css";
import React, { useState, useEffect, useImperativeHandle } from "react";
import PropTypes from "prop-types";

const Counter = React.forwardRef(({ initialCount }, ref) => {
const [count, setCount] = useState(initialCount);

const handleIncrementClick = (inc = 1) => {
setCount((count) => count + inc);
};

const handleDecrementClick = (dec = 1) => {
setCount((count) => count - dec);
};

useImperativeHandle(ref, () => ({
decrement: handleDecrementClick,
increment: handleIncrementClick
}));

return (
<div>
count: {count}
<hr />
<button onClick={() => handleDecrementClick()}>-</button>{" "}
<button onClick={() => handleIncrementClick()}>+</button>
</div>
);
});

Counter.propTypes = { initialCount: PropTypes.number.isRequired };

export default function App() {
const incrementButtonRef = React.useRef();

useEffect(() => {
if (incrementButtonRef.current) {
incrementButtonRef.current.increment(10);
}
}, [incrementButtonRef]);

return (
<div className="App">
<Counter initialCount={10} ref={incrementButtonRef} />
<button onClick={() => incrementButtonRef.current.increment(-10)}>
-10
</button>
</div>
);
}

Son bir not olarak forwardRef kullandığımız durumlarda forwardRef kullanımını propTypes ve defaultProps tanımlamaları öncesinde yapılmalı. Aksi durumda defaultPropslar kullanılamıyor.

 Sonraki yazıda görüşmek üzere.

logoblog

Thanks for reading React.forwarRef + React.useImperativeHandle kullanımı

Previous
« Prev Post

Hiç yorum yok:

Yorum Gönder