Module 8: State Management & Context

ඔබේ යෙදුම පුරා දත්ත පහසුවෙන් බෙදාගන්නා ආකාරය ඉගෙන ගනිමු.

1. State Management යනු කුමක්ද? Prop Drilling ගැටලුව

React/Next.js යෙදුමක State යනු, කාලයත් සමග වෙනස් විය හැකි, යෙදුමේ UI එක render වීමට බලපාන දත්ත වේ. උදාහරණයක් ලෙස, form input එකක අගය, user login වී ඇත්ද නැද්ද යන තත්ත්වය, dark mode on ද off ද යන්න state වේ.

සාමාන්‍යයෙන්, parent component එකක ඇති state එකක් child component එකකට ලබා දෙන්නේ props හරහාය. මෙය සරල යෙදුම් වලදී හොඳින් ක්‍රියාත්මක වේ. නමුත්, යෙදුම විශාල වන විට, ගැටලුවක් මතු වේ.

උදාහරණයක් ලෙස, App -> Layout -> Navbar -> UserAvatar යන component tree එකේ, `user` object එක `App` component එකේ සිට `UserAvatar` component එක දක්වා pass කිරීමට, `Layout` සහ `Navbar` යන components දෙකම හරහා "drill" කිරීමට සිදු වේ.

2. React Context API: Prop Drilling සඳහා විසඳුම

React Context API යනු prop drilling ගැටලුවට React මගින්ම ලබා දෙන විසඳුමයි. Context මගින් අපිට ඉඩ සලසනවා, component tree එක හරහා props manually pass නොකර, "global" ලෙස සැලකිය හැකි state එකක් නිර්මාණය කර, එය අවශ්‍ය ඕනෑම component එකකට කෙලින්ම ලබා ගැනීමට.

Dark mode theme, authentication status, language settings වැනි යෙදුම පුරාම අවශ්‍ය වන දත්ත කළමනාකරණයට Context API ඉතාමත් සුදුසුයි.

Context API භාවිතා කරන ආකාරය (පියවර 3)

  1. Context එක නිර්මාණය කිරීම (`createContext`):

    මුලින්ම, state එක තැන්පත් කිරීමට context object එකක් නිර්මාණය කළ යුතුයි. සාමාන්‍යයෙන් මේ සඳහා project root එකේ `context` නමින් folder එකක් සාදයි.

    // File: context/ThemeContext.js
    import { createContext } from 'react';
    
    const ThemeContext = createContext();
    
    export default ThemeContext;
    
  2. Provider එකෙන් App එක Wrap කිරීම:

    Context object එක සමග `Provider` නමින් component එකක් ලැබේ. අපිට global state එකට access අවශ්‍ය සියලුම components, මෙම `Provider` එකෙන් wrap කළ යුතුයි. Provider එකේ `value` prop එකට, අපිට share කිරීමට අවශ්‍ය state එක සහ එය වෙනස් කරන functions ලබා දිය යුතුයි.

    // We can create a custom Provider component
    // File: context/ThemeProvider.js
    import { useState } from 'react';
    import ThemeContext from './ThemeContext';
    
    export function ThemeProvider({ children }) {
      const [theme, setTheme] = useState('light');
    
      const toggleTheme = () => {
        setTheme(prevTheme => (prevTheme === 'light' ? 'dark' : 'light'));
      };
    
      return (
        <ThemeContext.Provider value={{ theme, toggleTheme }}>
          {children}
        </ThemeContext.Provider>
      );
    }
    
    // Then in pages/_app.js:
    import { ThemeProvider } from '../context/ThemeProvider';
    
    function MyApp({ Component, pageProps }) {
      return (
        <ThemeProvider>
          <Component {...pageProps} />
        </ThemeProvider>
      );
    }
    
  3. Context එක භාවිතා කිරීම (`useContext` hook):

    දැන් Provider එකෙන් wrap වූ ඕනෑම child component එකක් තුළ, `useContext` hook එක භාවිතා කර, `Provider` එකේ `value` එකට ලබා දුන් දත්ත (state සහ functions) කෙලින්ම ලබාගත හැක.

    // File: components/ThemeToggleButton.js
    import { useContext } from 'react';
    import ThemeContext from '../context/ThemeContext';
    
    export default function ThemeToggleButton() {
      const { theme, toggleTheme } = useContext(ThemeContext);
    
      return (
        <button onClick={toggleTheme}>
          Switch to {theme === 'light' ? 'Dark' : 'Light'} Mode
        </button>
      );
    }
    

දැක්කාද? `ThemeToggleButton` එකට කිසිදු prop එකක් pass කළේ නැත. එයට අවශ්‍ය state එක කෙලින්ම `ThemeContext` එකෙන් ලැබුණි.

3. Redux Toolkit (විකල්ප)

Context API කුඩා සහ මධ්‍යම ප්‍රමාණයේ යෙදුම් සඳහා ඉතාමත් ප්‍රයෝජනවත් වේ. නමුත් යෙදුමේ state එක ඉතාමත් සංකීර්ණ වන විට (state updates වලට middleware අවශ්‍ය වන, performance optimization අවශ්‍ය වන අවස්ථා), Redux වැනි වඩාත් потужний state management library එකක් භාවිතා කිරීම සුදුසු විය හැක.

Redux Toolkit යනු Redux භාවිතා කිරීම වඩාත් සරල සහ කාර්යක්ෂම කරන, Redux කණ්ඩායම විසින්ම නිර්දේශ කරන ලද library එකයි. එහි boilerplate code අඩු අතර, state management සඳහා හොඳම practices අනුගමනය කිරීමට උදව් කරයි. මෙම පාඨමාලාවේදී අපි Redux ගැඹුරින් සාකච්ඡා නොකළත්, ඔබේ state management අවශ්‍යතා සංකීර්ණ වන විට, Redux Toolkit ගැන සොයා බැලීම වටී.

4. Hands-on: Global Dark Mode Toggle එකක් සෑදීම

දැන් අපි ඉහත උදාහරණයේ පියවර අනුගමනය කර, අපේ Next.js යෙදුමට සම්පූර්ණ dark mode functionality එකක් Context API භාවිතයෙන් එකතු කරමු.

  1. Context සහ Provider සෑදීම:

    Project root එකේ `context` නමින් folder එකක් සාදන්න. ඒ තුළ `ThemeContext.js` සහ `ThemeProvider.js` යන files දෙක ඉහත පියවර 2 හි උදාහරණයේ ඇති පරිදිම සාදන්න.

  2. `_app.js` Wrap කිරීම:

    `pages/_app.js` file එකට ගොස්, ඔබේ යෙදුම `ThemeProvider` එකෙන් wrap කරන්න (මෙයද ඉහත උදාහරණයේ ඇත).

  3. Toggle Button එක සෑදීම:

    `components` folder එක තුළ `ThemeToggleButton.js` නමින් file එකක් සාදා, ඉහත පියවර 3 හි උදාහරණයේ ඇති code එක ඇතුළත් කරන්න.

  4. Layout එකට Button එක සහ Styles එකතු කිරීම:

    දැන් අපේ `Layout` component එකට (හෝ `Navbar` එකට) ගොස්, `ThemeToggleButton` එක import කර භාවිතා කරමු. ඒ සමගම, theme එකට අනුව background color එක වෙනස් වන ලෙස style එකක්ද එකතු කරමු.

    // File: app/layout.js (or wherever your main layout is)
    // Assuming this is a client component as it uses hooks
    'use client'; 
    import { useContext } from 'react';
    import ThemeContext from '../context/ThemeContext';
    import ThemeToggleButton from '../components/ThemeToggleButton';
    
    export default function Layout({ children }) {
      const { theme } = useContext(ThemeContext);
    
      return (
        <div className={theme}> {/* Add theme class to the root div */}
          <style jsx global>{`
            body {
              transition: background-color 0.3s ease;
            }
            .light {
              background-color: #ffffff;
              color: #000000;
            }
            .dark {
              background-color: #1a202c;
              color: #ffffff;
            }
          `}</style>
    
          <nav>
            {/* Your other nav items */}
            <ThemeToggleButton />
          </nav>
          <main>{children}</main>
        </div>
      );
    }
    
  5. පරීක්ෂා කිරීම:

    දැන් app එක run කර බලන්න. "Switch to Dark Mode" button එක click කළ විට, app එකේ background color එක සහ text color එක වෙනස් විය යුතුයි. ඔබ දැන් සාර්ථකව global state එකක් Context API මගින් කළමනාකරණය කර ඇත!