הוספת אינטראקטיביות

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

מגיבים לאירועים

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

רכיבים מובנים כמו <button> תומכים רק באירועי דפדפן מובנים כמו onClick. עם זאת, אתה יכול גם ליצור רכיבים משלך, ולתת לprops שלהם למטפל באירועים כל שמות פרטים לאפליקציה שאתה אוהב.

export default function App() {
  return (
    <Toolbar
      onPlayMovie={() => alert('Playing!')}
      onUploadImage={() => alert('Uploading!')}
    />
  );
}

function Toolbar({ onPlayMovie, onUploadImage }) {
  return (
    <div>
      <Button onClick={onPlayMovie}>
        Play Movie
      </Button>
      <Button onClick={onUploadImage}>
        Upload Image
      </Button>
    </div>
  );
}

function Button({ onClick, children }) {
  return (
    <button onClick={onClick}>
      {children}
    </button>
  );
}

Ready to learn this topic?

קרא את להגיב לאירועים כדי ללמוד כיצד להוסיף מטפלי אירועים.

Read More

מצב: זיכרון של רכיב

רכיבים צריכים לעשות את מה שמופיע על המסך כמו מאינטראקציה. הקלדה בטופס אמורה לעדכן את שדה הקלט, לחיצה על “הבא” בקרוסלת תמונה אמורה לשנות איזו תמונה מוצגת, לחיצה על “קנה” מכניסה מוצר לסל הקניות. רכיבים צריכים “לזכור” דברים: ערך הקלט הנוכחית, התמונה הנוכחית, עגלת הקניות. ב-React, סוג זה של זיכרון מיוחד לרכיב נקרא מצב.

אתה יכול להוסיף מצב לרכיב עם useState Hook. הHooks הם פונקציות מיוחדות האפשרויות לרכיבים שלך להשתמש בתכונות React (מצב אחד מהתכונות הללו). ה- useState Hook יכול לך להכריז על ניהול מצב. זה לוקח את הstate ההתחלתי ומחזיר ערכים זוג: ה__T_5__ הנוכחית ופונקציה קובעת מצב שמאפשרת לעדכן אותו.

const [index, setIndex] = useState(0);
const [showMore, setShowMore] = useState(false);

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

import { useState } from 'react';
import { sculptureList } from './data.js';

export default function Gallery() {
  const [index, setIndex] = useState(0);
  const [showMore, setShowMore] = useState(false);
  const hasNext = index < sculptureList.length - 1;

  function handleNextClick() {
    if (hasNext) {
      setIndex(index + 1);
    } else {
      setIndex(0);
    }
  }

  function handleMoreClick() {
    setShowMore(!showMore);
  }

  let sculpture = sculptureList[index];
  return (
    <>
      <button onClick={handleNextClick}>
        Next
      </button>
      <h2>
        <i>{sculpture.name} </i>
        by {sculpture.artist}
      </h2>
      <h3>
        ({index + 1} of {sculptureList.length})
      </h3>
      <button onClick={handleMoreClick}>
        {showMore ? 'Hide' : 'Show'} details
      </button>
      {showMore && <p>{sculpture.description}</p>}
      <img
        src={sculpture.url}
        alt={sculpture.alt}
      />
    </>
  );
}

Ready to learn this topic?

קרא את מצב: זיכרון של רכיב כדי ללמוד לזכור ערך ולעדכן אותו באינטראקציה.

Read More

עיבוד וביצוע

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

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

  1. הפעלת עיבוד (משלוח הזמנת הסועד למטבח)
  2. עיבוד הרכיב (הכנת ההזמנה במטבח)
  3. מתחייב ל-DOM (ביצוע ההזמנה על השולחן)
  1. React as a server in a restaurant, fetching orders from the users and delivering them to the Component Kitchen.
    Trigger
  2. The Card Chef gives React a fresh Card component.
    Render
  3. React delivers the Card to the user at their table.
    Commit

Illustrated by Rachel Lee Nabors

Ready to learn this topic?

קרא את render and Commit כדי ללמוד את המחזור החיים של עדכון ממשק משתמש.

Read More

מצב כתמונת מצב

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

console.log(count); // 0
setCount(count + 1); // Request a re-render with 1
console.log(count); // Still 0!

התנהגות זו עוזרת לך להימנע מבאגים עדינים. הנה אפליקציית צ’אט קטנה. נסו לנחש מה קורה אם תלחצו תחילה על “שלח” ואחר כך תשנה את הנמען לבוב. שמו של מי יופיע ב’התראה’ חמש שניות מאוחר יותר?

import { useState } from 'react';

export default function Form() {
  const [to, setTo] = useState('Alice');
  const [message, setMessage] = useState('Hello');

  function handleSubmit(e) {
    e.preventDefault();
    setTimeout(() => {
      alert(`You said ${message} to ${to}`);
    }, 5000);
  }

  return (
    <form onSubmit={handleSubmit}>
      <label>
        To:{' '}
        <select
          value={to}
          onChange={e => setTo(e.target.value)}>
          <option value="Alice">Alice</option>
          <option value="Bob">Bob</option>
        </select>
      </label>
      <textarea
        placeholder="Message"
        value={message}
        onChange={e => setMessage(e.target.value)}
      />
      <button type="submit">Send</button>
    </form>
  );
}

Ready to learn this topic?

קרא את מצב כתמונת מצב כדי לדעת מה הstate נראה “קבוע” ולא מדורגות בתוך הרופאי המקומות.

Read More

תור לסדרה של עדכוני state

רכיב זה הוא באגי: לחיצה על “+3” מגדילה את הניקוד פעם אחת בלבד.

import { useState } from 'react';

export default function Counter() {
  const [score, setScore] = useState(0);

  function increment() {
    setScore(score + 1);
  }

  return (
    <>
      <button onClick={() => increment()}>+1</button>
      <button onClick={() => {
        increment();
        increment();
        increment();
      }}>+3</button>
      <h1>Score: {score}</h1>
    </>
  )
}

State as a Snapshot מסביר מדוע זה קורה. הגדרת בקשת עיבוד מחדש חדש, אך לא משנה אותו בקוד פועל. אז ‘ציון’ ממשיך להיות ‘0’ מיד אחרי שאתה קורא ל’setScore(score + 1)‘.

console.log(score); // 0
setScore(score + 1); // setScore(0 + 1);
console.log(score); // 0
setScore(score + 1); // setScore(0 + 1);
console.log(score); // 0
setScore(score + 1); // setScore(0 + 1);
console.log(score); // 0

אתה יכול לתקן זאת על העברת פונקציית עדכון בעת הגדרת הstate. שימו לב כיצד החלפת setScore(score + 1) ב-setScore(s => s + 1) מתקנת את כפתור “+3”. זה יכול לך להכנס לפי עדכוני מצב מרובים.

import { useState } from 'react';

export default function Counter() {
  const [score, setScore] = useState(0);

  function increment() {
    setScore(s => s + 1);
  }

  return (
    <>
      <button onClick={() => increment()}>+1</button>
      <button onClick={() => {
        increment();
        increment();
        increment();
      }}>+3</button>
      <h1>Score: {score}</h1>
    </>
  )
}

Ready to learn this topic?

קרא את לעמוד בתור סדרה של עדכוני state כדי ללמוד כיצד להעמיד את הרצף של עדכוני state בתור.

Read More

עדכון אובייקטים בstate

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

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

import { useState } from 'react';

export default function Form() {
  const [person, setPerson] = useState({
    name: 'Niki de Saint Phalle',
    artwork: {
      title: 'Blue Nana',
      city: 'Hamburg',
      image: 'https://i.imgur.com/Sd1AgUOm.jpg',
    }
  });

  function handleNameChange(e) {
    setPerson({
      ...person,
      name: e.target.value
    });
  }

  function handleTitleChange(e) {
    setPerson({
      ...person,
      artwork: {
        ...person.artwork,
        title: e.target.value
      }
    });
  }

  function handleCityChange(e) {
    setPerson({
      ...person,
      artwork: {
        ...person.artwork,
        city: e.target.value
      }
    });
  }

  function handleImageChange(e) {
    setPerson({
      ...person,
      artwork: {
        ...person.artwork,
        image: e.target.value
      }
    });
  }

  return (
    <>
      <label>
        Name:
        <input
          value={person.name}
          onChange={handleNameChange}
        />
      </label>
      <label>
        Title:
        <input
          value={person.artwork.title}
          onChange={handleTitleChange}
        />
      </label>
      <label>
        City:
        <input
          value={person.artwork.city}
          onChange={handleCityChange}
        />
      </label>
      <label>
        Image:
        <input
          value={person.artwork.image}
          onChange={handleImageChange}
        />
      </label>
      <p>
        <i>{person.artwork.title}</i>
        {' by '}
        {person.name}
        <br />
        (located in {person.artwork.city})
      </p>
      <img
        src={person.artwork.image}
        alt={person.artwork.title}
      />
    </>
  );
}

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

{
  "dependencies": {
    "immer": "1.7.3",
    "react": "latest",
    "react-dom": "latest",
    "react-scripts": "latest",
    "use-immer": "0.5.1"
  },
  "scripts": {
    "start": "react-scripts start",
    "build": "react-scripts build",
    "test": "react-scripts test --env=jsdom",
    "eject": "react-scripts eject"
  },
  "devDependencies": {}
}

Ready to learn this topic?

קרא את עדכון אובייקטים בstate כדי ללמוד כיצד לעדכן אובייקטים בצורה נכונה.

Read More

עדכון מערכים בstate

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

import { useState } from 'react';

const initialList = [
  { id: 0, title: 'Big Bellies', seen: false },
  { id: 1, title: 'Lunar Landscape', seen: false },
  { id: 2, title: 'Terracotta Army', seen: true },
];

export default function BucketList() {
  const [list, setList] = useState(
    initialList
  );

  function handleToggle(artworkId, nextSeen) {
    setList(list.map(artwork => {
      if (artwork.id === artworkId) {
        return { ...artwork, seen: nextSeen };
      } else {
        return artwork;
      }
    }));
  }

  return (
    <>
      <h1>Art Bucket List</h1>
      <h2>My list of art to see:</h2>
      <ItemList
        artworks={list}
        onToggle={handleToggle} />
    </>
  );
}

function ItemList({ artworks, onToggle }) {
  return (
    <ul>
      {artworks.map(artwork => (
        <li key={artwork.id}>
          <label>
            <input
              type="checkbox"
              checked={artwork.seen}
              onChange={e => {
                onToggle(
                  artwork.id,
                  e.target.checked
                );
              }}
            />
            {artwork.title}
          </label>
        </li>
      ))}
    </ul>
  );
}

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

{
  "dependencies": {
    "immer": "1.7.3",
    "react": "latest",
    "react-dom": "latest",
    "react-scripts": "latest",
    "use-immer": "0.5.1"
  },
  "scripts": {
    "start": "react-scripts start",
    "build": "react-scripts build",
    "test": "react-scripts test --env=jsdom",
    "eject": "react-scripts eject"
  },
  "devDependencies": {}
}

Ready to learn this topic?

קרא את עדכון מערכים בstate כדי ללמוד לעדכן מערכים בצורה נכונה.

Read More

מה הלאה?

עברו אל מגיבים לאירועים כדי להתחיל לקרוא פרק זה עמוד אחר עמוד!

לחלופין, אם אתה כבר מכיר את הנושאים האלה, למה שלא תקרא על Managing State?