ה-useState hook - מדריך מקיף PlatoBlockchain Data Intelligence. חיפוש אנכי. איי.

ה-useState hook - מדריך מקיף

מהי מדינה?

לפני שנצלול עמוק לתוך ה- useState hook, בואו נבין תחילה את המונח מדינה.

מצב מייצג מידע על משהו בנקודת זמן נתונה.

לדוגמה, הבה נשקול תיבת טקסט.

בתחילה, אין שום דבר בתוך תיבת הטקסט הזו, אז המצב שלה הוא ריק. נניח שתתחיל להקליד בתוכו Hello, עבור כל לחיצת מקש ישתנה מצב תיבת הטקסט. בהתחלה זה יהיה "H", אחר כך "הוא", ואז "הל" וכן הלאה עד שזה יהפוך ל"שלום".

כמו כן, שים לב שבזמן שאתה מקליד, אתה לא מאבד את הערך הקודם. אם תלחץ על "H" ואחריו "e" אתה מקבל "He" ולא רק "e". במילים אחרות אתה יכול לחשוב על המדינה כעל זיכרון של תיבת הטקסט.

הצורך במדינה ברכיב React.

בואו נבין זאת בעזרת דוגמה.

Codesanbox ללא מדינה

כאן יש לנו א ClickCounter רכיב המציג את מספר הפעמים שנלחץ על כפתור ההגדלה.

אנו משתמשים בא משתנה מקומי "מונה" כדי לשמור על ספירת הקליקים.

בכל פעם שאנו לוחצים על כפתור הגדל, handleClick הפונקציה תופעל. פונקציה זו תגדיל את ערך המונה ב-1 וגם תירשם את הערך בקונסולה.

קדימה, לחץ על כפתור הגדל בתצוגה המקדימה של CodeSandbox.

שום דבר לא קרה?

ובכן, נראה שההיגיון שלנו נכון. הערך שנרשם בקונסולה (CodeSandbox) מתעדכן כראוי בכל פעם שאנו לוחצים, אך מדוע העדכון הזה לא בא לידי ביטוי בממשק המשתמש?

זה בגלל הדרך שבה React עובדת.

  • שינויים במשתנים מקומיים אינם מפעילים עיבוד מחדש.
  • במהלך רינדור מחדש, רכיב נוצר מאפס, כלומר פונקציה של רכיב (בדוגמה זו היא הפונקציה ClickCounter) מבוצעת שוב. מכיוון שמשתנים (לדוגמה, מונה) הם מקומיים לפונקציה, הערכים הקודמים שלהם הולכים לאיבוד.

אז איך נגרום לרכיב לזכור ערכים בין עיבודים?

כן, הבנת נכון! אנו עושים זאת בעזרת ה useState וו.

הוק של useState

ה-useState hook מספק מנגנונים לשמר את המצב ולהפעיל עיבוד מחדש.

בואו נסתכל על השימוש בו.

import React, { useState } from "react";
const state = useState(initialValue);

// OR

const state = React.useState(initialValue);

ה-useState hook מחזיר מערך המכיל שני פריטים:

  • A משתנה מצב ששומר על ערכיו במהלך עיבוד מחדש. הערך הראשוני המועבר ל-useState מוקצה למשתנה המצב במהלך העיבוד הראשון.
  • A פונקציית קובע שמעדכן את משתנה המצב וגם מפעיל עיבוד מחדש.
const state = useState(0);
const data = state[0];
const setData = state[1];

שימוש ביטול מבנה של מערך , נוכל לחדש את ההצהרות לעיל להצהרה אחת, כפי שמוצג להלן:

const [data, setData] = useState(0);

הערך הראשוני המועבר ל-useState משמש רק במהלך העיבוד הראשון. עבור עיבוד מחדש, זה מתעלם.

מונה עם useState

כעת, בואו נעדכן את דוגמה המונה הקודמת כך שתכלול את ה-useState hook.

  • מכיוון שאנו צריכים את ערך המונה בין רינדור מחדש, בואו נמיר אותו למצב.
const [counter, setCounter] = useState(0);
  • קורא ל-setCounter בתוך פונקציית handleClick.
const handleClick = () => {
  setCounter(counter + 1);
  console.log(`%c Counter:${counter}`, "color:green");
};

הפונקציה setCounter תעדכן את ערך המונה ב-1 ותפעיל עיבוד מחדש. כאשר הפונקציה של הרכיב נקראת בעיבוד מחדש למשתנה המצב המוחזר על ידי useState יהיה הערך המעודכן.

נסה את CodeSandbox עם הקוד המעודכן. לחץ על כפתור הגדל וראה את הקסם של UseState בפעולה.

Codesanbox עם useState

אתה יכול לוודא שבעיבוד מחדש, הרכיב הפונקציונלי ClickCounter נקרא שוב על ידי צפייה ביומני המסוף. היומן "ClickCounter start" שמתווסף בתחילת הרכיב יירשם בכל עיבוד.

עיבוד ראשון

עיבוד מחדש

פונקציית עדכון

נניח שאנו רוצים להגדיל את הערך של מונה ב-4 בכל קליק.

const handleClick = () => {
  setCounter(counter + 1);
    setCounter(counter + 1);
    setCounter(counter + 1);
    setCounter(counter + 1);
    console.log(`%c Counter:${counter}`, "color:green");
    };

נניח שהערך ההתחלתי של מונה הוא 0. מה אתה מצפה לראות לאחר לחיצה על הכפתור?

ללא פונקציית עדכון

ציפית שהספירה תהיה 4 נכון? אבל למה אתה רואה 1 במקום?

א) כל עיבוד משויך למדינה. הערך של המדינה הזו נשאר נעול לכל החיים של העיבוד הזה.

שימו לב שהיומן בתוך הפונקציה handleClick מדפיס את ערך המונה כ-0.

לא משנה כמה פעמים תקרא לשיטת setCounter, הערך של המונה נשאר זהה.

const handleClick = () => {
  setCounter(counter + 1);
    setCounter(counter + 1);
    setCounter(counter + 1);
    setCounter(counter + 1);
    console.log(`%c Counter:${counter}`, "color:green");
    };
ב) עד שיבוצע כל הקוד בתוך מטפל באירועים, React לא יפעיל רינדור מחדש.

מסיבה זו כל קריאת setCounter לא מפעילה עיבוד בודד. במקום זאת, React מוסיף את פונקציות המגדיר הללו בתור. מבצע אותם בסדר שהם היו בתור. העדכונים שנעשו למדינה לאחר ביצוע כל ההצהרות באים לידי ביטוי בעיבוד הבא. תור זה של עדכוני מצב מרובים ידוע בשם אצווה. זה מאפשר ל-React להיות ביצועי יותר.

לכן, כאן אנו מקבלים רינדור בודד במקום 4 רינדורים שונים.

דוגמה זו פשוטה ותוכל לתקן בעיה זו על ידי עדכון הקוד כפי שמוצג להלן:

const handleClick = () => {
setCounter(counter + 4);
    console.log(`%c Counter:${counter}`, "color:green");
    };

אבל מה אם היה לך מקרה שימוש שבו אתה רוצה לעדכן את המצב מספר פעמים לפני העיבוד הבא.

זה המקום שבו ה_ עדכון פונקציית _ שימושית.

אנו יכולים לשחזר את הדוגמה הקודמת עם פונקציית העדכון באופן הבא:

const handleClick = () => {
  setCounter(prevCounter => prevCounter + 1);
    setCounter(prevCounter => prevCounter + 1);
    setCounter(prevCounter => prevCounter + 1);
    setCounter(prevCounter => prevCounter + 1);
    console.log(`%c Counter:${counter}`, "color:green");
    };

כאן prevCounter ⇒ prevCounter + 1 מייצג את פונקציית העדכון.

כפי שהוסבר קודם לכן, הצהרות העדכון הללו נמצאות גם בתור (אצווה).

פונקציית העדכון מקבלת מצב בהמתנה/קודם שבו היא משתמשת כדי לחשב את המצב הבא.

עדכון פונקציות אצווה

להלן CodeSandbox עם פונקציית העדכון שנוספה. נסה ללחוץ על כפתור ההגדלה.

ארגז חול של פונקציית Updater

פונקציית אתחול

תסתכל על הדוגמה למטה. כאן אנו קוראים לפונקציה getItems כדי לקבל את הערך ההתחלתי עבור המדינה.

import React from "react";
import { useState } from "react";
function ListItems() { 
  const getItems = () => { 
    console.log(`%c getItems called`, "color:hotpink");
    	return Array(50).fill(0); 
    }; 
  const [items, setItems] = useState(getItems()); 
    
    return ( 
    	<div className="card">
        <ul> {items.map((item, index) => 
        	( <li key={index}>Item {index + 1}		</li>))} 
        </ul> <button onClick={() => setItems([...items, 0])}>Add Item</button> 	</div> );
} 
export default ListItems;

פונקציה זו יוצרת מערך בגודל 50 וממלאת את המערך באפסים. עיין בתמונה למטה.

מערך מלא ב-50 אפסים

פריטים אלה מוצגים לאחר מכן על המסך.

הכל נראה בסדר אבל יש לנו בעיה כאן.

לחץ על הוסף פריט לחצן (ממוקם אחרי רשימת הפריטים) כדי להוסיף פריט חדש לרשימה. התבונן ביומנים.

ללא פונקציית אתחול

אתה רואה את הבעיה כאן?

היומן "getItems called" יתווסף לקונסולה בכל פעם שאתה מוסיף פריט. המשמעות היא שהפונקציה הזו נקראת בכל עיבוד.

זכור ש-useState מתעלם מהערך ההתחלתי המועבר אליו לאחר הרינדור הראשון, אך כאן הערך ההתחלתי עדיין בחישוב מחדש. זה יכול להיות יקר אם אנחנו יוצרים מערכים גדולים או מבצעים חישובים כבדים.

נוכל לפתור בעיה זו על ידי מעבר getItems בתור _ אתחול פונקציה _.

כעת, בואו נעשה שינוי קטן בקוד.

const [items, setItems] = useState(getItems);

עם פונקציית אתחול

ראה את חלון המסוף ב-CodeSandbox. שימו לב שיומן "getItems called" מודפס רק בעיבוד הראשון. כאשר פריטים הבאים מתווספים יומן זה אינו קיים.

למרות שאין הבדל ויזואלי בין שתי הדוגמאות, מבחינת ביצועים הן שונות.

זכור כאשר אתה צריך פונקציה עבור המצב ההתחלתי, תמיד להעביר את הפונקציה או לקרוא לפונקציה בתוך פונקציה אחרת. לעולם אל תתקשר ישירות לפונקציה.

✅ const [items, setItems] = useState(getItems);
✅ const [items, setItems] = useState(() => getItems());
❌ const [items, setItems] = useState(getItems());

כמה ווים של UseState יכולים להיות לי

אתה יכול לקבל כמה ווים של useState בתוך רכיב שהוא דורש.

ראה את CodeSandbox

ווים לשימוש מרובים

לרכיב שלהלן יש שלושה מצבים שונים - שם משתמש, סיסמה, keepMeSignedIn.

נסה לעדכן את הערכים של שם המשתמש, keepMeSignedIn. המצבים המעודכנים נרשמים במסוף כאשר לוחצים על כפתור ההתחברות.

עיקרי הדברים

  • useState מספק מנגנון להפעיל עיבוד מחדש ולהתמיד במצב בין עיבוד מחדש.
  • השתמש בפונקציית העדכון כאשר אתה צריך:
    • חשב את המצב הבא על סמך המצב הקודם.
    • בצע עדכונים מרובים למדינה לפני העיבוד הבא.
  • אם המצב הראשוני מתקבל מפונקציה - השתמש בתחביר פונקציית האתחול.
  • יכולים להיות ווים מרובים של useState בתוך רכיב.

אהבת את הפוסט הזה? שתף אותו עם אחרים.
נכתב במקור עבור הבלוג האישי שלי - https://gauravsen.com/use-state-hook

בול זמן:

עוד מ עובדת תגובת קודמטור