Q6. Giải thích về forwardRef và useImperativeHandle trong React Native?
forwardRef
trong React được sử dụng để chuyển tiếp một ref qua một component tới một element con. Điều này hữu ích khi bạn cần truy cập trực tiếp đến một DOM node hoặc một instance của một component con từ một component cha, mà không muốn phá vỡ tính đóng gói của component con
Sử dụng forwardRef
Để minh họa forwardRef
và tính đóng gói trong React, hãy xem xét một ví dụ trong đó một component cha cần truy cập trực tiếp đến một phần tử DOM trong component con để thực hiện một hành động cụ thể, chẳng hạn như focus vào một input. Thông thường, component con không để lộ DOM node của nó, giữ cho cấu trúc và hành vi của nó được đóng gói. Tuy nhiên, bằng cách sử dụng forwardRef component cha có thể đạt được mục đích này mà không vi phạm nguyên tắc đóng gói
Giả sử chúng ta có một component cha tên là ParentComponent
và một component con tên là TextInput
. ParentComponent
muốn focus vào TextInput
khi một nút được nhấn.
Bước 1: Tạo TextInput
component sử dụng forwardRef
import React, { forwardRef } from 'react';
import { TextInput as RNTextInput } from 'react-native';
const TextInput = forwardRef((props, ref) => {
return <RNTextInput ref={ref} {...props} />;
});
export default TextInput;
Ở đây, TextInput là một component nhận ref từ component cha và chuyển tiếp ref đó đến phần tử RNTextInput của React Native
Bước 2: Tạo ParentComponent
để sử dụng TextInput
import React, { useRef } from 'react';
import { View, Button } from 'react-native';
import TextInput from './TextInput'; // Đảm bảo import đúng đường dẫn
const ParentComponent = () => {
const inputRef = useRef(null);
const focusInput = () => {
if (inputRef.current) {
inputRef.current.focus();
}
};
return (
<View>
<TextInput ref={inputRef} placeholder="Enter text here" />
<Button title="Focus the input" onPress={focusInput} />
</View>
);
};
export default ParentComponent;
Giải thích:
Tính đóng gói: TextInput component duy trì tính đóng gói bằng cách không trực tiếp expose bất kỳ chi tiết triển khai nào của nó. Nó chỉ nhận ref từ forwardRef và chuyển tiếp ref đó đến phần tử RNTextInput
Sử dụng
forwardRef
: TextInput sử dụng forwardRef để nhận và chuyển tiếp ref. Điều này cho phép ParentComponent có thể truy cập và tương tác trực tiếp với DOM node của TextInputComponent cha: ParenComponent tạo một ref bằng useRef và truyền ref đó vào TextInput. Khi nút focus được nhấn, hàm focusInput sẽ được gọi, và inputRef.current.focus() sẽ focus vào input element.
Khi nào nên sử dụng forwardRef
?
Khi cần truy cập trực tiếp đến DOM node: Khi component cha cần truy cập hoặc thao tác trực tiếp trên DOM node của component con.
Giữ nguyên tính đóng gói: Khi bạn muốn giữ tính đóng gói của component con, không để lộ chi tiết triển khai ra ngoài.
Sử dụng HOCs: Khi bạn sử dụng Higher Order Components và cần chuyển tiếp
ref
đến component gốc.
Sử dụng forwardRef
và useImperativeHandle
Trong React, việc truyền callback từ component cha vào component con là một cách phổ biến để gọi một method từ component cha. Tuy nhiên để đảm bảo tính đóng gói và tránh việc truyền callback qua props, bạn có thể sử dụng forwardRef
kết hợp với useImperativeHandle
. Điều này cho phép bạn expose một số method cụ thể của component con để component cha có thể gọi trực tiếp thông qua ref
Bước 1: Tạo component con sử dụng forwardRef
và useImperativeHandle
import React, { useImperativeHandle, forwardRef, useRef } from 'react';
import { TextInput as RNTextInput, Button, View, Text } from 'react-native';
const TextInput = forwardRef((props, ref) => {
const inputRef = useRef(null);
// Expose methods to parent component
useImperativeHandle(ref, () => ({
focus: () => {
inputRef.current.focus();
},
clear: () => {
inputRef.current.clear();
},
}));
return <RNTextInput ref={inputRef} {...props} />;
});
export default TextInput;
Ở đây, TextInput
component sử dụng forwardRef
để chuyển tiếp ref
từ component cha. useImperativeHandle
được sử dụng để expose các method focus
và clear
.
Bước 2: Tạo component cha để sử dụng các method của component con
import React, { useRef } from 'react';
import { View, Button } from 'react-native';
import TextInput from './TextInput'; // Đảm bảo import đúng đường dẫn
const ParentComponent = () => {
const inputRef = useRef(null);
const focusInput = () => {
if (inputRef.current) {
inputRef.current.focus();
}
};
const clearInput = () => {
if (inputRef.current) {
inputRef.current.clear();
}
};
return (
<View>
<TextInput ref={inputRef} placeholder="Enter text here" />
<Button title="Focus the input" onPress={focusInput} />
<Button title="Clear the input" onPress={clearInput} />
</View>
);
};
export default ParentComponent;
Giải thích:
Component con (
TextInput
): Sử dụngforwardRef
để nhậnref
từ component cha vàuseImperativeHandle
để expose các methodfocus
vàclear
.Component cha (
ParentComponent
): Tạo mộtref
bằnguseRef
và truyềnref
đó vàoTextInput
. Khi các nút "Focus the input" và "Clear the input" được nhấn, các method tương ứng được gọi thông quainputRef.current
.
Khi nào nên sử dụng useImperativeHandle
?
Khi cần expose method cụ thể từ component con: Khi bạn muốn component cha có thể gọi một số method cụ thể của component con mà không cần truyền callback qua props.
Giữ nguyên tính đóng gói: Khi bạn muốn giữ tính đóng gói của component con, không muốn để lộ chi tiết triển khai ra ngoài.