একটি ব্রাউজার DOM নোডে React কম্পোনেন্ট দেখানোর জন্য createRoot আপনাকে একটি root তৈরী করতে দেবে।

const root = createRoot(domNode, options?)

রেফারেন্স

createRoot(domNode, options?)

একটি ব্রাউজার DOM এলিমেন্টে React কম্পোনেন্ট দেখানোর স্বার্থে একটি React root তৈরী করার জন্য createRoot কল করুন।

import { createRoot } from 'react-dom/client';

const domNode = document.getElementById('root');
const root = createRoot(domNode);

React domNode এর জন্য একটি root তৈরী করবে, এবং এর মধ্যকার DOM পরিচালনার দায়িত্ব নিয়ে নিবে। root তৈরী করবার পর আপনাকে এর মধ্যে একটি React কম্পোনেন্ট দেখাবার জন্য root.render কল করতে হবেঃ

root.render(<App />);

সম্পূর্ণরূপে React দিয়ে বানানো একটি অ্যাপে সাধারণত একটি মাত্র createRoot কল থাকবে এর root কম্পোনেন্টের জন্য। যেই পেইজের বিভিন্ন অংশের জন্য React এর “ছিটেফোটা” ব্যবহৃত হয় সেগুলোতে যত গুলো ইচ্ছে আলাদা আলাদা root থাকতে পারে।

নিচে আরো উদাহরণ দেখ…

প্যারামিটার

  • domNode: একটা DOM এলিমেন্ট। React এই DOM এলিমেন্টের জন্য একটি root তৈরী করবে এবং root এ আপনাকে ফাংশন কল করতে দেবে, যেমন হতে পারে রেন্ডার হওয়া React কম্পোনেন্ট দেখানোর জন্য ফাংশন render

  • optional options: এই React root এর জন্য বিভিন্ন option সংবলিত একটি অবজেক্ট।

    • optional onCaughtError: যখন React একটি Error Boundary-তে কোন error ধরে তখন কল হওয়া কলব্যাক। Error Boundary যে error ধরেছে এবং componentStack সংবলিত একটি errorInfo অবজেক্ট দিয়ে কল হয়।
    • optional onUncaughtError: যখন কোন error throw হয় কিন্তু Error Boundary দিয়ে ধরা হয় না তখন কল হওয়া কলব্যাক। যে error throw হয়েছে এবং componentStack সংবলিত একটি errorInfo অবজেক্ট দিয়ে কল হয়।
    • optional onRecoverableError: যখন React স্বয়ংক্রিয়ভাবে error থেকে recover করে তখন কল হওয়া কলব্যাক। React যে error throw করে এবং componentStack সংবলিত একটি errorInfo অবজেক্ট দিয়ে কল হয়। কিছু recoverable error-এ মূল error কারণ error.cause হিসেবে অন্তর্ভুক্ত থাকতে পারে।
    • optional identifierPrefix: useId দিয়ে তৈরী হওয়া ID গুলোর জন্য React যে string prefix ব্যবহার করে। একই পেইজে যখন একাধিক root থাকে তখন conflict এড়াতে এটা কাজে লাগে।

রিটার্ন

createRoot দুটি মেথডসহ একটি অব্জেক্ট রিটার্ন করেঃ render এবং unmount.

যেসব বিষয়ে সতর্ক থাকতে হবে

  • আপনার অ্যাপ যদি সার্ভার থেকে রেন্ডার হয়, createRoot() কাজ করবে না। বরং hydrateRoot() ব্যব্যহার করুন।
  • খুব সম্ভবত আপনার অ্যাপে একটি মাত্র createRoot কল থাকবে। আপনি যদি একটি ফ্রেমওয়ার্ক ব্যবহার করেন, সম্ভবতঃ সে-ই আপনার হয়ে কলটি করে দিবে।
  • যখন আপনি DOM ট্রি-এর অন্য একটি অংশে যা আপনার কম্পোনেন্টের চাইল্ড না(উদাহরণস্বরূপ একটা মোডাল বা টুলটিপ), JSX রেন্ডার করতে চাইবেন তখন createRoot এর বদলে createPortal ব্যবহার করুন।

root.render(reactNode)

React root-এর ব্রাউজার DOM নোডে কোন JSX (“React node”) দেখানোর জন্য root.render কল করুন।

root.render(<App />);

React root-এ <App /> দেখাবে, এবং এর মধ্যকার DOM পরিচালনার দায়িত্ব নিয়ে নিবে।

নিচে আরো উদাহরণ দেখুন।

প্যারামিটার

  • reactNode: আপনি দেখাতে চান এমন একটি React নোড। এটা সাধারণত <App /> এর মত এক টুকরো JSX হবে।, কিন্তু আপনি createElement() দিয়ে তৈরী করা একটি React এলিমেন্ট, একটি স্ট্রিং, একটি সংখ্যা, null বা undefined ও পাস করতে পারেন।

রিটার্ন

root.render রিটার্ন করে undefined.

সতর্কতা

  • আপনি যখন প্রথম বারের মত root.render কল করবেন, React এর রুটের ভিতরে কম্পোনেন্ট রেন্ডার করবার আগে থাকা সব HTML কনটেন্ট মুছে ফেলবে।

  • যদি আপনার রুটের DOM নোডে এমন HTML থাকে যা React সার্ভারে তৈরি করেছে বা বিল্ডের সময় তৈরি করেছে, তাহলে বরং hydrateRoot() ব্যবহার করুন, যা বিদ্যমান HTML এ ইভেন্ট হ্যান্ডলারগুলো যুক্ত করে দেয়।

  • আপনি যদি একি রুটে একাধিকবার render কল করেন, তাহলে আপনার পাঠানো সর্বশেষ JSX দেখানোর খাতিরে React প্রয়োজনমত DOM আপডেট করে ফেলবে। React আগেরবার রেন্ডার হওয়া ট্রি এর সাথে “মিলিয়ে দেখবে” এবং সিদ্ধান্ত নিবে DOM এর কোণ অংশগুলো পুনর্ব্যবহার করা যায় আর কোনগুলো আবার বানাতে হবে। একই রুটে আবার render কল করা রুট কম্পোনেন্টে set function কল করার মতঃ React অপ্রয়োজনীয় DOM আপডেট এড়ানোর চেষ্টা করে।

  • যদিও rendering শুরু হওয়ার পর synchronous, root.render(...) synchronous নয়। এর মানে হল root.render() এর পরের কোড ওই নির্দিষ্ট render এর কোন effects (useLayoutEffect, useEffect) fire হওয়ার আগেই রান হতে পারে। এটা সাধারণত ঠিক আছে এবং খুব কমই adjustment প্রয়োজন হয়। বিরল ক্ষেত্রে যেখানে effect timing গুরুত্বপূর্ণ, আপনি root.render(...) কে flushSync দিয়ে wrap করতে পারেন যাতে initial render সম্পূর্ণভাবে synchronously রান হয়।

    const root = createRoot(document.getElementById('root'));
    root.render(<App />);
    // 🚩 HTML এ এখনো rendered <App /> অন্তর্ভুক্ত হবে নাঃ
    console.log(document.body.innerHTML);

root.unmount()

React রুটের মধ্যে রেন্ডার হওয়া একটি ট্রি মুছে ফেলতে root.unmount কল করুন।

root.unmount();

সম্পূর্ণরূপে React দিয়ে বানানো অ্যাপের সাধারণত root.unmount এ কোন কল থাকে না।

এটা সে ক্ষেত্রে সবচেয়ে কাজে লাগে যদি অন্য কোন কোডের কারণে DOM থেকে আপনার React রুটের DOM নোড (বা ট্রিতে এর কোন পূর্বসূরী) মুছে যায়। উদাহরণস্বরূপ, ধরেন একটা jQuery ট্যাব প্যানেল আছে যা DOM থেকে অচল ট্যাবগুলোকে ফেলে দেয়। যদি একটা ট্যাব ফেলে দেওয়া হয়, তাহলে এই ট্যাবের মধ্যে থাকা যাবতীয় সব কিছু(ভিতরকার React রুটগুলো সহ) DOM থেকে মুছে যায়। সেক্ষেত্রে, root.unmount কল করার মাধ্যমে আপনার React কে বলতে হবে মুছে যাওয়া রুটের কনটেন্ট ম্যানেজ করা “বন্ধ” করতে। না হলে, মুছে যাওয়া রুটের ভেতরকার কম্পোনেন্ট সাবস্ক্রিপশনের মত global resource মুছবে না এবং সেগুলো ফ্রি হবে না।

root.unmount কল করলে রুটের সব কম্পোনেন্ট আনমাউন্ট হবে এবং রুট DOM নোড থেকে React “detach” হয়ে যাবে। একই সাথে ট্রিতে কোন ইভেন্ট হ্যান্ডলার বা স্টেট থাকলে সেটাও মুছে যাবে।

প্যারামিটার

root.unmount কোন প্যারামিটার গ্রহণ করে না।

রিটার্ন

root.unmount undefined রিটার্ন করে।

সতর্কতা

  • root.unmount কল করলে ট্রি-এর সকল কম্পোনেন্ট আনমাউন্ট হবে এবং React কে রুট DOM নোড থেকে “বিচ্ছিন” করবে।

  • একবার root.unmount কল করা হলে একই রুটে root.render আর কল করা যাবে না। আনমাউন্ট করা রুটে root.render কলের চেষ্টা করা হলে “Cannot update an unmounted root” এরর দেখাবে। যদিও, আপনি একই DOM নোডে নতুন রুট তৈরী করতে পারেন যখন সেই নোডে আগের রুট আনমাউন্ট করা হয়ে গেছে।


ব্যবহার

সম্পূর্ণরূপে React দিয়ে তৈরি অ্যাপের রেন্ডারিং

যদি আপনার অ্যাপটি সম্পূর্ণরূপে React দিয়ে বানানো হয়ে থাকে, তবে পুরো অ্যাপের জন্য একটি মাত্র রুট তৈরি করুন।

import { createRoot } from 'react-dom/client';

const root = createRoot(document.getElementById('root'));
root.render(<App />);

সাধারণত, আপনাকে একবারই শুরুতে এই কোড রান করতে হবে। এটা যা করবে তা হলঃ

  1. আপনার HTML এ ডিফাইন্ড হওয়া ব্রাউজার DOM নোড খুঁজে বের করবে।
  2. আপনার অ্যাপের ভেতর থাকা React কম্পোনেন্ট দেখাবে।
import { createRoot } from 'react-dom/client';
import App from './App.js';
import './styles.css';

const root = createRoot(document.getElementById('root'));
root.render(<App />);

যদি আপনার অ্যাপটি সম্পূর্ণরূপে React দিয়ে বানানো হয়ে থাকে, আপনার আর কোন রুট তৈরির বা আবার root.render কল করার প্রয়োজন হবার কথা না

এর পর থেকে, React আপনার পুরো অ্যাপের DOM পরিচালনা করবে। আরো কম্পোনেন্ট যুক্ত করবার জন্য App কম্পোনেন্টে তাদের nest করুন। যখন আপনার UI আপডেটের প্রয়োজন হবে, আপনার প্রতিটি কম্পোনেন্ট স্টেট ব্যবহার করে সেটা করতে পারবে। যখন আপনার DOM নোডের বাইরে অতিরিক্ত কোন কনটেন্ট যেমন একটা মোডাল বা টুলটিপ দেখানোর প্রয়োজন হবে তখন, একটা পোর্টাল ব্যবহার করে সেটা রেন্ডার করুন।

খেয়াল করুন

যখন আপনার HTML খালি থাকে, যতক্ষণ পর্যন্ত জাভাস্ক্রিপ্ট লোড এবং রান না হয়, ততক্ষণ ব্যবহারকারী একটা খালি পেইজ দেখবে।

<div id="root"></div>

বিষয়টা খুব ধীর রকম অনুভূত হতে পারে! এটা সমাধানের জন্য, আপনি বিল্ডের সময় বা সার্ভারে আপনার কম্পোনেন্ট গুলো থেকে প্রাথমিক HTML তৈরি করে ফেলতে পারেন। এর পরে আপনার ভিজিটররা জাভাস্ক্রিপ্ট লোড হবার আগেই টেক্সট পড়তে, ছবি দেখতে এবং লিঙ্ক ক্লিক করতে পারবে। আমাদের উপদেশ থাকবে যে আপনি এর জন্য একটা ফ্রেমওয়ার্ক ব্যবহার করুন যা নিজেই এই অপটিমাইজেশনটুকু করে দেবে। কখন এটা রান করছে তার উপর নির্ভর করে একে বলা হয়, server-side rendering (SSR) অথবা static site generation (SSG)।

সতর্কতা

যেসব অ্যাপ server rendering বা static generation ব্যবহার করে তাদেরকে অবশ্যই createRoot এর বদলে hydrateRoot কল করতে হবে। React তখন আপনার HTML থেকে DOM নোডগুলো ধ্বংস এবং পুনরায় তৈরি করার বদলে hydrate (পুনর্ব্যবহার) করবে।


React দিয়ে আংশিকভাবে বানানো পেইজের রেন্ডারিং

যদি আপনার পেইজ সম্পূর্ণরূপে React দিয়ে বানানো না হয়ে থাকে, React দিয়ে পরিচালিত প্রতিটি উচ্চ স্তরের UI piece এর জন্য একটি রুট তৈরি করার খাতিরে আপনি একাধিকবার createRoot কল করতে পারেন। আপনি root.render কল করার মাধ্যমে প্রতিটি রুটে ভিন্ন ভিন্ন কনটেন্ট দেখাতে পারেন।

এখানে, দুটি ভিন্ন React কম্পোনেন্ট index.html এর দুটি DOM নোডে রেন্ডার হচ্ছেঃ

import './styles.css';
import { createRoot } from 'react-dom/client';
import { Comments, Navigation } from './Components.js';

const navDomNode = document.getElementById('navigation');
const navRoot = createRoot(navDomNode); 
navRoot.render(<Navigation />);

const commentDomNode = document.getElementById('comments');
const commentRoot = createRoot(commentDomNode); 
commentRoot.render(<Comments />);

আপনি document.createElement() ব্যবহার করে একটা নতুন DOM নোড তৈরীও করতে পারেন এবং একে নিজে নিজে ডকুমেন্টে যোগ করতে পারেন।

const domNode = document.createElement('div');
const root = createRoot(domNode);
root.render(<Comment />);
document.body.appendChild(domNode); // আপনি ডকুমেন্টের যেকোন জায়গায় এটা যোগ করতে পারেন

DOM নোড থেকে React ট্রি সরাতে এবং এর ব্যবহৃত সকল রিসোর্স মুছে ফেলতে root.unmount কল করুন।

root.unmount();

এইটা সাধারণত সবচেয়ে কাজে লাগে যদি অ্যাপের ভিতরে থাকা আপনার React কম্পোনেন্টগুলো ভিন্ন কোন ফ্রেমওয়ার্কে লেখা থাকে।


একটি রুট কম্পোনেন্ট আপডেট করা

আপনি একই রুটে একাধিকবার render কল করতে পারেন। যতক্ষণ পর্যন্ত আগে থেকে রেন্ডার হওয়া অবস্থার সাথে কম্পোনেন্ট ট্রি এর গঠনবিন্যাস মিলে যাচ্ছজে, React state সংরক্ষণ করবে। খেয়াল করুন যে আপনি ইনপুটে টাইপ করতে পারছেন, যার অর্থ প্রতি সেকেন্ডে পুনারবৃত্ত হওয়া render কল ধ্বংসাত্মক নয়ঃ

import { createRoot } from 'react-dom/client';
import './styles.css';
import App from './App.js';

const root = createRoot(document.getElementById('root'));

let i = 0;
setInterval(() => {
  root.render(<App counter={i} />);
  i++;
}, 1000);

সাধারণত render একাধিকবার কল করা হয় না, বরং আপনার কম্পোনেট গুলোই state আপডেট করে।

প্রোডাকশনে Error logging

ডিফল্টভাবে, React সকল error কনসোলে log করে। আপনার নিজস্ব error reporting implement করার জন্য, আপনি optional error handler root options onUncaughtError, onCaughtError এবং onRecoverableError প্রদান করতে পারেনঃ

import { createRoot } from "react-dom/client";
import { reportCaughtError } from "./reportError";

const container = document.getElementById("root");
const root = createRoot(container, {
onCaughtError: (error, errorInfo) => {
if (error.message !== "Known error") {
reportCaughtError({
error,
componentStack: errorInfo.componentStack,
});
}
},
});

onCaughtError অপশন হল একটি ফাংশন যা দুটি argument দিয়ে কল হয়ঃ

  1. যে error throw হয়েছে।
  2. একটি errorInfo অবজেক্ট যাতে error এর componentStack রয়েছে।

onUncaughtError এবং onRecoverableError এর সাথে একত্রে, আপনি আপনার নিজস্ব error reporting system implement করতে পারেনঃ

import { createRoot } from "react-dom/client";
import App from "./App.js";
import {
  onCaughtErrorProd,
  onRecoverableErrorProd,
  onUncaughtErrorProd,
} from "./reportError";

const container = document.getElementById("root");
const root = createRoot(container, {
  // মনে রাখবেন development এ এই options গুলো সরিয়ে দিন যাতে
  // React এর default handlers ব্যবহার করতে পারেন বা development এর জন্য আপনার নিজস্ব overlay implement করতে পারেন।
  // handlers গুলো এখানে শুধুমাত্র demonstration উদ্দেশ্যে unconditionally specify করা হয়েছে।
  onCaughtError: onCaughtErrorProd,
  onRecoverableError: onRecoverableErrorProd,
  onUncaughtError: onUncaughtErrorProd,
});
root.render(<App />);

Troubleshooting

একটা রুট তৈরী করবার পরও কিছুই দেখাচ্ছে না

নিশ্চিত করুন যে আপনি আসলেই রুটে আপনার অ্যাপ রেন্ডার করতে ভুলে যাননি।

import { createRoot } from 'react-dom/client';
import App from './App.js';

const root = createRoot(document.getElementById('root'));
root.render(<App />);

আপনি এটা করার আগ পর্যন্ত কিছুই দেখা যাবে না।


একটা এরর দেখাচ্ছেঃ “You passed a second argument to root.render”

একটি সাধারণ ভুল হল createRoot এর options root.render(...) এ পাঠানোঃ

Console
Warning: You passed a second argument to root.render(…) but it only accepts one argument.

এটা ঠিক করতে, root options root.render(...) এ না দিয়ে createRoot(...) এ দিনঃ

// 🚩 ভুলঃ root.render শুধুমাত্র একটি argument নেয়।
root.render(App, {onUncaughtError});

// ✅ সঠিকঃ options createRoot এ দিন।
const root = createRoot(container, {onUncaughtError});
root.render(<App />);

একটা এরর দেখাচ্ছেঃ “Target container is not a DOM element”

এই এররের অর্থ হল, আপনি যা createRoot-এ পাঠাচ্ছেন তা DOM নোড না।

আপনি যদি নিশ্চিত না হন যে কি হচ্ছে, একে logging করার চেষ্টা করুনঃ

const domNode = document.getElementById('root');
console.log(domNode); // ???
const root = createRoot(domNode);
root.render(<App />);

উদাহরণস্বরূপ, যদি domNode null হয়, এর অর্থ getElementByIdnull রিটার্ন করেছে। এটা হবে যদি আপনার কল করার সময়ে ডকুমেন্টে ওই ID এর কোন নোড না থাকে। এর কিছু কারণ হতে পারে এমনঃ

  1. হতে পারে আপনার যেই ID খুজছেন সেটা আপনার HTML এ ব্যবহার করা ID থেকে আলাদা। টাইপিং এ ভুল হয়েছে কি নিশ্চিত হন!
  2. হয়ত আপনার বান্ডলের <script> ট্যাগ HTML-এ এর পরে কোন DOM নোড “দেখতে” পারছে না।

এই এরর পাবার আরেকটি কমন কারণ হল createRoot(domNode) এর বদলে createRoot(<App />) লেখা।


I’m getting an error: “Functions are not valid as a React child.”

এই এররের অর্থ হল, আপনি যা root.render এ পাঠাচ্ছেন তা React কম্পোনেন্ট নয়।

এটা হতে পারে যদি আপনি root.render কে <Component /> এর বদলে Component দিয়ে কল করেনঃ

// 🚩 ভুলঃ অ্যাপ একটা ফাংশন, কম্পোনেন্ট না।
root.render(App);

// ✅ সঠিকঃ: <App /> একটা কম্পোনেন্ট।
root.render(<App />);

অথবা যদি আপনি root.render এ একটা ফাংশন পাঠিয়ে থাকেন, যেখানে আসলে এই ফাংশন কলের ফলাফল পাঠাবার কথাঃ

// 🚩 ভুলঃ createApp একটা ফাংশন, কম্পোনেন্ট না।
root.render(createApp);

// ✅ সঠিকঃ একটা কম্পোনেন্ট রিটার্ন করার জন্য createApp কল করুন।
root.render(createApp());

সার্ভার থেকে রেন্ডার হওয়া HTML একদম শুরু থেকে তৈরী হচ্ছে

যদি আপনার অ্যাপ সার্ভার থেকে রেন্ডার হয়ে থাকে এবং React এর তৈরী করা ইনিশিয়াল HTML থাকে ওতে, আপনি খেয়াল করবেন যে root.render কল করলে সব HTML মুছে যায়, এবং একদম শুরু থেকে সব DOM নোড তৈরি হয়। এটা ধীরতর হতে পারে, ফোকাস এবং স্ক্রল পজিশন রিসেট হয়ে যায়, এবং ব্যবহারকারীর ইনপুটও হারিয়ে যেতে পারে।

সার্ভার থেকে রেন্ডার হওয়া অ্যাপের ক্ষেত্রে অবশ্যই createRoot এর বদলে hydrateRoot এর ব্যবহার করতে হবেঃ

import { hydrateRoot } from 'react-dom/client';
import App from './App.js';

hydrateRoot(
document.getElementById('root'),
<App />
);

খেয়াল করুন এর API আলাদা। বিশেষ করে, আর কোন root.render কল হবে না।