Reducer மற்றும் Context மூலம் scale செய்தல்
Reducers ஒரு component-ன் state update logic-ஐ consolidate செய்ய அனுமதிக்கின்றன. Context, information-ஐ மற்ற components-க்கு ஆழமாக pass செய்ய அனுமதிக்கிறது. Complex screen-ன் state manage செய்ய reducers மற்றும் context-ஐ ஒன்றாக combine செய்யலாம்.
நீங்கள் கற்றுக்கொள்ள போவது
- Reducer-ஐ context உடன் combine செய்வது எப்படி
- State மற்றும் dispatch-ஐ props வழியாக pass செய்வதைத் தவிர்ப்பது எப்படி
- Context மற்றும் state logic-ஐ தனி file-இல் வைத்திருப்பது எப்படி
Reducer-ஐ context உடன் combine செய்தல்
Reducers அறிமுகம் பகுதியில் இருந்து வரும் இந்த example-இல், state reducer மூலம் manage செய்யப்படுகிறது. Reducer function எல்லா state update logic-ஐயும் கொண்டுள்ளது; அது இந்த file-ன் கீழே declare செய்யப்பட்டுள்ளது:
import { useReducer } from 'react'; import AddTask from './AddTask.js'; import TaskList from './TaskList.js'; export default function TaskApp() { const [tasks, dispatch] = useReducer( tasksReducer, initialTasks ); function handleAddTask(text) { dispatch({ type: 'added', id: nextId++, text: text, }); } function handleChangeTask(task) { dispatch({ type: 'changed', task: task }); } function handleDeleteTask(taskId) { dispatch({ type: 'deleted', id: taskId }); } return ( <> <h1>கியோட்டோவில் விடுமுறை நாள்</h1> <AddTask onAddTask={handleAddTask} /> <TaskList tasks={tasks} onChangeTask={handleChangeTask} onDeleteTask={handleDeleteTask} /> </> ); } function tasksReducer(tasks, action) { switch (action.type) { case 'added': { return [...tasks, { id: action.id, text: action.text, done: false }]; } case 'changed': { return tasks.map(t => { if (t.id === action.task.id) { return action.task; } else { return t; } }); } case 'deleted': { return tasks.filter(t => t.id !== action.id); } default: { throw Error('தெரியாத action: ' + action.type); } } } let nextId = 3; const initialTasks = [ { id: 0, text: 'Philosopher’s Path', done: true }, { id: 1, text: 'கோவிலுக்கு செல்', done: false }, { id: 2, text: 'Matcha குடி', done: false } ];
Reducer event handlers-ஐ short மற்றும் concise ஆக வைத்திருக்க உதவுகிறது. ஆனால் உங்கள் app வளரும்போது, இன்னொரு சிரமத்தைச் சந்திக்கலாம். தற்போது tasks state மற்றும் dispatch function top-level TaskApp component-இல் மட்டுமே available. பிற components tasks list-ஐ read செய்யவோ மாற்றவோ, current state மற்றும் அதை மாற்றும் event handlers-ஐ props ஆக explicit ஆக pass down செய்ய வேண்டும்.
உதாரணமாக, TaskApp tasks list மற்றும் event handlers-ஐ TaskList-க்கு pass செய்கிறது:
<TaskList
tasks={tasks}
onChangeTask={handleChangeTask}
onDeleteTask={handleDeleteTask}
/>மேலும் TaskList event handlers-ஐ Task-க்கு pass செய்கிறது:
<Task
task={task}
onChange={onChangeTask}
onDelete={onDeleteTask}
/>இதுபோன்ற சிறிய example-இல் இது நன்றாக வேலை செய்கிறது; ஆனால் நடுவில் பத்து அல்லது நூறு components இருந்தால், எல்லா state மற்றும் functions-ஐ pass down செய்வது மிகவும் சிரமமாக இருக்கும்!
அதனால், props வழியாக pass செய்வதற்கான alternative ஆக, tasks state மற்றும் dispatch function இரண்டையும் context-க்குள் வைக்க விரும்பலாம். இவ்வாறு, tree-இல் TaskApp-க்கு கீழே உள்ள எந்த component-உம் repetitive “prop drilling” இல்லாமல் tasks-ஐ read செய்து actions dispatch செய்ய முடியும்.
Reducer-ஐ context உடன் combine செய்வது இப்படி:
- Context-ஐ create செய்யுங்கள்.
- State மற்றும் dispatch-ஐ context-க்குள் put செய்யுங்கள்.
- Tree-இல் எங்கும் context-ஐ use செய்யுங்கள்.
Step 1: Context-ஐ create செய்யுங்கள்
useReducer Hook current tasks மற்றும் அவற்றை update செய்ய அனுமதிக்கும் dispatch function-ஐ return செய்கிறது:
const [tasks, dispatch] = useReducer(tasksReducer, initialTasks);அவற்றை tree-க்குள் pass down செய்ய, இரண்டு separate contexts-ஐ create செய்வீர்கள்:
TasksContextcurrent tasks list-ஐ provide செய்கிறது.TasksDispatchContextcomponents actions dispatch செய்ய அனுமதிக்கும் function-ஐ provide செய்கிறது.
பிற files-இலிருந்து பின்னர் import செய்ய, அவற்றை தனி file-இலிருந்து export செய்யுங்கள்:
import { createContext } from 'react'; export const TasksContext = createContext(null); export const TasksDispatchContext = createContext(null);
இங்கே, இரண்டு contexts-க்கும் default value ஆக null pass செய்கிறீர்கள். Actual values TaskApp component மூலம் provide செய்யப்படும்.
Step 2: State மற்றும் dispatch-ஐ context-க்குள் வையுங்கள்
இப்போது உங்கள் TaskApp component-இல் இரண்டு contexts-ஐயும் import செய்யலாம். useReducer() return செய்த tasks மற்றும் dispatch-ஐ எடுத்து, கீழுள்ள முழு tree-க்கும் provide செய்யுங்கள்:
import { TasksContext, TasksDispatchContext } from './TasksContext.js';
export default function TaskApp() {
const [tasks, dispatch] = useReducer(tasksReducer, initialTasks);
// ...
return (
<TasksContext value={tasks}>
<TasksDispatchContext value={dispatch}>
...
</TasksDispatchContext>
</TasksContext>
);
}இப்போதைக்கு, information-ஐ props வழியாகவும் context-இலுமாக இரண்டிலும் pass செய்கிறீர்கள்:
import { useReducer } from 'react'; import AddTask from './AddTask.js'; import TaskList from './TaskList.js'; import { TasksContext, TasksDispatchContext } from './TasksContext.js'; export default function TaskApp() { const [tasks, dispatch] = useReducer( tasksReducer, initialTasks ); function handleAddTask(text) { dispatch({ type: 'added', id: nextId++, text: text, }); } function handleChangeTask(task) { dispatch({ type: 'changed', task: task }); } function handleDeleteTask(taskId) { dispatch({ type: 'deleted', id: taskId }); } return ( <TasksContext value={tasks}> <TasksDispatchContext value={dispatch}> <h1>கியோட்டோவில் விடுமுறை நாள்</h1> <AddTask onAddTask={handleAddTask} /> <TaskList tasks={tasks} onChangeTask={handleChangeTask} onDeleteTask={handleDeleteTask} /> </TasksDispatchContext> </TasksContext> ); } function tasksReducer(tasks, action) { switch (action.type) { case 'added': { return [...tasks, { id: action.id, text: action.text, done: false }]; } case 'changed': { return tasks.map(t => { if (t.id === action.task.id) { return action.task; } else { return t; } }); } case 'deleted': { return tasks.filter(t => t.id !== action.id); } default: { throw Error('தெரியாத action: ' + action.type); } } } let nextId = 3; const initialTasks = [ { id: 0, text: 'Philosopher’s Path', done: true }, { id: 1, text: 'கோவிலுக்கு செல்', done: false }, { id: 2, text: 'Matcha குடி', done: false } ];
அடுத்த step-இல் prop passing-ஐ remove செய்வீர்கள்.
Step 3: Tree-இல் எங்கும் context பயன்படுத்துங்கள்
இப்போது tasks list அல்லது event handlers-ஐ tree-க்குள் கீழே pass செய்ய வேண்டியதில்லை:
<TasksContext value={tasks}>
<TasksDispatchContext value={dispatch}>
<h1>கியோட்டோவில் விடுமுறை நாள்</h1>
<AddTask />
<TaskList />
</TasksDispatchContext>
</TasksContext>அதற்கு பதிலாக, task list தேவைப்படும் எந்த component-உம் அதை TasksContext-இலிருந்து read செய்யலாம்:
export default function TaskList() {
const tasks = useContext(TasksContext);
// ...Task list-ஐ update செய்ய, எந்த component-உம் context-இலிருந்து dispatch function-ஐ read செய்து call செய்யலாம்:
export default function AddTask() {
const [text, setText] = useState('');
const dispatch = useContext(TasksDispatchContext);
// ...
return (
// ...
<button onClick={() => {
setText('');
dispatch({
type: 'added',
id: nextId++,
text: text,
});
}}>சேர்</button>
// ...TaskApp component எந்த event handlers-ஐயும் கீழே pass செய்யவில்லை; TaskList கூட Task component-க்கு எந்த event handlers-ஐயும் pass செய்யவில்லை. ஒவ்வொரு component-உம் தன்னுக்குத் தேவையான context-ஐ read செய்கிறது:
import { useState, useContext } from 'react'; import { TasksContext, TasksDispatchContext } from './TasksContext.js'; export default function TaskList() { const tasks = useContext(TasksContext); return ( <ul> {tasks.map(task => ( <li key={task.id}> <Task task={task} /> </li> ))} </ul> ); } function Task({ task }) { const [isEditing, setIsEditing] = useState(false); const dispatch = useContext(TasksDispatchContext); let taskContent; if (isEditing) { taskContent = ( <> <input value={task.text} onChange={e => { dispatch({ type: 'changed', task: { ...task, text: e.target.value } }); }} /> <button onClick={() => setIsEditing(false)}> சேமி </button> </> ); } else { taskContent = ( <> {task.text} <button onClick={() => setIsEditing(true)}> திருத்து </button> </> ); } return ( <label> <input type="checkbox" checked={task.done} onChange={e => { dispatch({ type: 'changed', task: { ...task, done: e.target.checked } }); }} /> {taskContent} <button onClick={() => { dispatch({ type: 'deleted', id: task.id }); }}> நீக்கு </button> </label> ); }
State இன்னும் top-level TaskApp component-இல்தான் “lives”; அது useReducer மூலம் manage செய்யப்படுகிறது. ஆனால் அதன் tasks மற்றும் dispatch இப்போது இந்த contexts-ஐ import செய்து பயன்படுத்துவதன் மூலம் tree-இல் கீழே உள்ள ஒவ்வொரு component-க்கும் available.
எல்லா wiring-யையும் ஒரு file-க்குள் நகர்த்துதல்
இதை கட்டாயம் செய்ய வேண்டியதில்லை, ஆனால் reducer மற்றும் context இரண்டையும் ஒரே file-க்குள் நகர்த்துவதால் components-ஐ இன்னும் சுத்தமாக்கலாம். தற்போது, TasksContext.js இரண்டு context declarations மட்டும் கொண்டுள்ளது:
import { createContext } from 'react';
export const TasksContext = createContext(null);
export const TasksDispatchContext = createContext(null);இந்த file இப்போது கொஞ்சம் நிரம்பப் போகிறது! Reducer-ஐ அதே file-க்குள் நகர்த்துவீர்கள். பிறகு அதே file-இல் புதிய TasksProvider component-ஐ declare செய்வீர்கள். இந்த component எல்லா pieces-ஐயும் ஒன்றாக இணைக்கும்:
- அது state-ஐ reducer மூலம் manage செய்யும்.
- அது கீழுள்ள components-க்கு இரண்டு contexts-ஐயும் provide செய்யும்.
- அதற்கு JSX pass செய்ய முடிவதற்காக, அது
children-ஐ prop ஆக எடுக்கும்.
export function TasksProvider({ children }) {
const [tasks, dispatch] = useReducer(tasksReducer, initialTasks);
return (
<TasksContext value={tasks}>
<TasksDispatchContext value={dispatch}>
{children}
</TasksDispatchContext>
</TasksContext>
);
}இது உங்கள் TaskApp component-இலிருந்து எல்லா complexity மற்றும் wiring-யையும் நீக்குகிறது:
import AddTask from './AddTask.js'; import TaskList from './TaskList.js'; import { TasksProvider } from './TasksContext.js'; export default function TaskApp() { return ( <TasksProvider> <h1>கியோட்டோவில் விடுமுறை நாள்</h1> <AddTask /> <TaskList /> </TasksProvider> ); }
Context-ஐ use செய்யும் functions-ஐயும் TasksContext.js-இலிருந்து export செய்யலாம்:
export function useTasks() {
return useContext(TasksContext);
}
export function useTasksDispatch() {
return useContext(TasksDispatchContext);
}ஒரு component context-ஐ read செய்ய வேண்டும்போது, இந்த functions வழியாக அதைச் செய்யலாம்:
const tasks = useTasks();
const dispatch = useTasksDispatch();இது behavior-ஐ எந்த வகையிலும் மாற்றாது, ஆனால் பின்னர் இந்த contexts-ஐ மேலும் split செய்யவோ அல்லது இந்த functions-ல் logic சேர்க்கவோ இது இடமளிக்கும். இப்போது context மற்றும் reducer wiring அனைத்தும் TasksContext.js-இல் உள்ளது. இதனால் components clean ஆகவும் uncluttered ஆகவும் இருந்து, data எங்கிருந்து வருகிறது என்பதற்குப் பதிலாக அவை என்ன display செய்கின்றன என்பதில் கவனம் செலுத்தும்:
import { useState } from 'react'; import { useTasks, useTasksDispatch } from './TasksContext.js'; export default function TaskList() { const tasks = useTasks(); return ( <ul> {tasks.map(task => ( <li key={task.id}> <Task task={task} /> </li> ))} </ul> ); } function Task({ task }) { const [isEditing, setIsEditing] = useState(false); const dispatch = useTasksDispatch(); let taskContent; if (isEditing) { taskContent = ( <> <input value={task.text} onChange={e => { dispatch({ type: 'changed', task: { ...task, text: e.target.value } }); }} /> <button onClick={() => setIsEditing(false)}> சேமி </button> </> ); } else { taskContent = ( <> {task.text} <button onClick={() => setIsEditing(true)}> திருத்து </button> </> ); } return ( <label> <input type="checkbox" checked={task.done} onChange={e => { dispatch({ type: 'changed', task: { ...task, done: e.target.checked } }); }} /> {taskContent} <button onClick={() => { dispatch({ type: 'deleted', id: task.id }); }}> நீக்கு </button> </label> ); }
TasksProvider-ஐ tasks-ஐ எப்படி கையாள வேண்டும் என்பதை அறிந்த screen-ன் ஒரு பகுதியாகவும், useTasks-ஐ அவற்றை read செய்வதற்கான வழியாகவும், useTasksDispatch-ஐ tree-இல் கீழே உள்ள எந்த component-இலிருந்தும் அவற்றை update செய்வதற்கான வழியாகவும் நினைக்கலாம்.
உங்கள் app வளரும்போது, இதுபோன்ற பல context-reducer pairs இருக்கலாம். Tree-இல் ஆழமாக உள்ள data-வை access செய்ய வேண்டியபோது, அதிக வேலை இல்லாமல் உங்கள் app-ஐ scale செய்யவும் state-ஐ மேலே உயர்த்தவும் இது ஒரு சக்திவாய்ந்த வழி.
Recap
- எந்த component-உம் மேலே உள்ள state-ஐ read செய்து update செய்ய reducer-ஐ context உடன் combine செய்யலாம்.
- State மற்றும் dispatch function-ஐ கீழுள்ள components-க்கு provide செய்ய:
- இரண்டு contexts-ஐ create செய்யுங்கள் (state-க்கும் dispatch functions-க்கும்).
- Reducer-ஐ பயன்படுத்தும் component-இலிருந்து இரண்டு contexts-ஐயும் provide செய்யுங்கள்.
- அவற்றை read செய்ய வேண்டிய components-இலிருந்து தேவையான context-ஐ use செய்யுங்கள்.
- எல்லா wiring-யையும் ஒரே file-க்குள் நகர்த்துவதன் மூலம் components-ஐ இன்னும் declutter செய்யலாம்.
- Context provide செய்யும்
TasksProviderபோன்ற component-ஐ export செய்யலாம். - அதை read செய்ய
useTasksமற்றும்useTasksDispatchபோன்ற custom Hooks-ஐயும் export செய்யலாம்.
- Context provide செய்யும்
- உங்கள் app-இல் இதுபோன்ற பல context-reducer pairs இருக்கலாம்.