• בלוג
  • המחשה פשוטה כדי להבין למה צריך להעביר פונקציה ל setState ב React

המחשה פשוטה כדי להבין למה צריך להעביר פונקציה ל setState ב React

15/01/2020

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

להרבה אנשים שמתחילים עם ריאקט יצא לעשות את הטעות הבאה ב Class Component:

class Counter {
  constructor() {
    this.state = { count: 0 };
  }

  inc = () => {
    this.setState({ count: this.state.count + 1 });
  }

  render() {
    return (
      <button onClick={this.inc}>{this.state.count}</button>
    );
  }
}

שזהה לטעות הבאה ב Functional Component:

function Counter() {
  const [count, setCount] = useState(0);

  function inc() {
    setCount(count + 1);
  }

  return (
    <button onClick={inc}>{count}</button>
  );
}

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

function Counter() {
  const [count, setCount] = useState(0);

  function inc() {
    const nextValue = count + 1;
    setCount(nextValue);
    setCount(nextValue);
  }

  return (
    <button onClick={inc}>{count}</button>
  );
}

או בגירסת הקלאסים:

class Counter {
  constructor() {
    this.state = { count: 0 };
  }

  inc = () => {
    const nextValue = this.state.count + 1;
    this.setState({ count: nextValue });
    this.setState({ count: nextValue });
  }

  render() {
    return (
      <button onClick={this.inc}>{this.state.count}</button>
    );
  }
}

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

  inc = () => {
    this.setState({ count: this.state.count + 1 });
    this.setState({ count: this.state.count + 1 });
  }

אני חושב שמה שהיה קצת מוזר ב Class Component והפך למאוד ברור במעבר ל Hooks הוא שהפונקציה setState לא משנה את הסטייט באופן מיידי אלא רק בפעם הבאה שיקרא render אז נקבל את הסטייט העדכני.