RPP এর doc অফিশিয়ালি আছে React Doc - Legacy তে । RPP মূলত Higher Order Components (HOC) এর এক্সটেন্ডেড ভার্সন, HOC এর থেকে বেটার সুবিধা পাওয়া যায় বলে এটা বহুল প্রচলিত । যদিও Hooks আসার পর HOC এর তেমন আর ব্যবহার হয় না কিন্তু RPP এখনও অনেক ক্ষেত্রে প্রয়োজন পরে ।
জনপ্রিয় Reactjs লাইব্রারি এর মধ্যে একটা React Router যা RPP ব্যবহার করে কাজ করে । (যদিও বর্তমান সময়ে পরিবর্তন হতে পারে) ।
উদাহরণঃ
import { BrowserRouter as Router, Route } from "react-router-dom";
const App = () => (
<Router>
<Route
path="/user"
render={() => <h1>User Page</h1>}
/>
</Router>
);
আবার, react-hook-form
এর Controller
component টাও কিন্তু Render Props দিয়েই করা, , বিস্তারিত Official Doc
উদাহরণঃ
<Controller
control={control}
name="ReactDatepicker"
render={({ field: { onChange, onBlur, value, ref } }) => (
<ReactDatePicker
onChange={onChange}
onBlur={onBlur}
selected={value}
/>
)}
/>
Render Props Pattern কিভাবে কাজ করে ?
Render Prop এমন একটি টেকনিক বোঝায় যা কোনও component প্রপ হিসাবে কোনও ফাংশন পাস করা , সেই ফাংশন দ্বারা পাস করা component কনডিশনালি বা ফাংশনালিটি অন্যযায়ী রেন্ডার করতে দেয়। Render Props শব্দটি render ও props এই ২টা শব্দ থেকে এসেছে । এখানে render নামের একটা props এর মধ্যে আমরা JSX পাস করেতে পারি আবার সেখানেই wrapper থেকে আমাদের লজিক লেখা ডাটা পেতেও পারি ।
যেমনঃ
<Title render={() => <h1> Hello, I am Yeasin !</h1>} />
এখানে আমরা Title
Component টা ইনভোক করা হল render নামে props দিয়ে । সাধারণত আমরা এক্ষেত্রে render
নামের একটা props
পাঠিয়ে JSX
পাস করি । এ থেকেই নাম হয়েছে render props
তো, এটা কাজ কিভাবে করল ?
const Title = (props) => props.render();
Title নামের এই Component টার দিকে একটু লক্ষ্য করি, এখানে props.render() এর এখানে কি হচ্ছে? মূলত আমাদের পাস করা render নামের Props টীর টাইপ JSX Element তাই JSX একটা ফাংশন যা react
আমাদের জন্য invocoke
করে দেয় তবে এক্ষেত্রে আমরা ম্প্যানুয়ালী করছি ।
এটাকে আরেকটু এক্সটেন্ড করি বিসারিত বুঝার জন্য ।
const Title = ({
render,
bgColor = "bg-gray-100",
}: {
render: () => React.ReactNode;
bgColor?: string;
}) => {
return (
<div className={`p-4 rounded-lg shadow-md ${bgColor}`}>
<h1 className="text-2xl font-bold text-blue-600">{render()}</h1>
<p className="text-sm text-gray-500 mt-2">
This is a dynamically styled title component.
</p>
</div>
);
};
এখন এটা ব্যবহার করতে চাইলে আমরা এভাবে করতে পারি ,
<Title bgColor="bg-yellow-100" render={() => <span>Dynamic Render Props!</span>} />
এখানে যদিও বেসিক এক্সাম্পল দেখানো হচ্ছে বুঝার সুবিধার্থে, তবে চাইলে এটাকে আমরা আরও এক্সটেন্ড করে নিতে পারব । render এর মধ্যে যেকোন কিছু দিয়ে সেই ডাইনামিক কিছু করতে পারব আবার props.render(); করার ক্ষেত্রে props.render({name: "Yeasin"});
এমন নানা Dynamic data চাইলে পাঠাতে পারব যা প্রয়োজনভেদে আলাদা আলাদা component টে ব্যবহার হলেও ভিন্ন ভিন্ন ভাবে দেখাতে পারবে ।
render কিভাবে UI তে দেখাচ্ছে,
যেহেতু render নামের props টি JSX Element পাঠাবে তাই সেটা সরাসরি invoke করা যায় । কিন্তু কিভাবে ?
<Title/>
Title()
এই ২টা মূলত একই, প্রতিটি Component আসলে Function যার কারণে আমরা এর নাম ফংশনাল কম্পোনেন্ট
বলে থাকি .
বাস্তব উদাহরণঃ
এক্ষেত্রে আমরা আমাদের সেই HOC তে দেখানো আগের component এর উদাহরণ কোডই আবারও Render props Pattern দিয়ে করে দেখাব ।
ফোল্ডার স্টাকচারঃ
/src
├── components
│ ├── FetchUsers.tsx <-- Render Props Component
│ ├── UserList.tsx <-- Uses FetchUsers
│ └── UserCard.tsx <-- (Optional) Single user item component
├── App.tsx
├── main.tsx
১। FetchUsers.tsx (Render Props Component)
import { useEffect, useState } from "react";
export interface User {
id: number;
name: string;
email: string;
}
interface FetchUsersProps {
render: (users: User[]) => JSX.Element;
}
const FetchUsers = ({ render }: FetchUsersProps) => {
const [users, setUsers] = useState<User[]>([]);
useEffect(() => {
fetch("https://jsonplaceholder.typicode.com/users")
.then((res) => res.json())
.then((data) => setUsers(data))
.catch((err) => console.error("Error fetching users:", err));
}, []);
return render(users);
// Or with any style: return <div> styling and then: render(users); </div>
};
export default FetchUsers;
২। UserCard.tsx (Optional: Single User Component)
import { User } from "./FetchUsers";
const UserCard = ({ user }: { user: User }) => {
return (
<li key={user.id} className="border-b p-2">
<strong>{user.name}</strong> - {user.email}
</li>
);
};
export default UserCard;
৩। UserList.tsx (Uses FetchUsers with Render Props)
import FetchUsers from "./FetchUsers";
import UserCard from "./UserCard";
const UserList = () => {
return (
<FetchUsers
render={(users) => (
<div className="rounded-lg bg-gray-100 p-4">
<h2 className="mb-2 text-lg font-bold">User List</h2>
<ul>
{users.map((user) => (
<UserCard key={user.id} user={user} />
))}
</ul>
</div>
)}
/>
);
};
export default UserList;
৪। App.tsx
import UserList from "./components/UserList";
const App = () => {
return (
<div className="container mx-auto p-4">
<UserList />
</div>
);
};
export default App;