useState هو Hook في React يتيح لك إضافة متغير حالة إلى مكونك

const [state, setState] = useState(initialState);

المرجع

useState(initialState)

استدعِ useState في الطبقة العليا لمكونك لتعريف متغير الحالة.

import { useState } from 'react';

function MyComponent() {
const [age, setAge] = useState(28);
const [name, setName] = useState('Taylor');
const [todos, setTodos] = useState(() => createTodos());
// ...

التقليد هو تسمية متغيرات الحالة بشكل مثل [something, setSomething] باستخدام [array destructuring] تفكيك الصفائف

انظر المزيد من الأمثلة أدناه

المعاملات

  • initialState: القيمة التي تريد أن تكون عليها الحالة في البداية. يمكن أن تكون قيمة من أي نوع، ولكن هناك سلوك خاص للدوال. يتم تجاهل هذه الحجة بعد التقديم الأولى

  • إذا مررت بدالة كـ initialState، سيتم التعامل معها كحالة التهيئة. يجب أن تكون نقية، ويجب ألا تأخذ أي حجج، ويجب أن تعيد قيمة من أي نوع. سيستدعي React وظيفة البادئ عند تهيئة المكون، ويقوم بتخزين قيمته المرتجعة كحالة أولية. انظر مثالاً أدناه.

المرجعات

useState ترجع قيمتين

  1. الحالة الحالية. خلال العرض الأولي، ستتطابق مع initialState التي قمت بتمريرها.
  2. الدالة set التي تمكنك من تحديث الحالة إلى قيمة مختلفة وتشغيل إعادة العرض.

التحذيرات

  • useState هو Hook، لذلك يمكنك تسميتها فقط *** في المستوى الأعلى من مكوناتك *** أو الخطاطيف الخاصة بك. لا يمكنك تسميتها داخل الحلقات أو الظروف. إذا كنت بحاجة إلى ذلك، استخراج عنصر جديد وانقل الدولة فيه.
  • في الوضع المقيد، يستدعي React *** وظيفة بدء التشغيل الخاصة بك مرتين *** من أجل [مساعدتك في العثور على الشوائب العرضية.] هذا سلوك تطويري فقط ولا يؤثر على الإنتاج. إذا كانت وظيفتك المبدئة نقية (كما ينبغي أن تكون)، فلا ينبغي أن يؤثر ذلك على السلوك. النتيجة من إحدى المكالمات سيتم تجاهلها.

set مثل, الوظائف setSomething(الحالة التالية)

تسمح لك الدالة set التي ترجعها useState بتحديث الحالة إلى قيمة مختلفة وتشغيل إعادة التقديم. يمكنك تمرير الحالة التالية مباشرة، أو دالة تحسبها من الحالة السابقة

const [name, setName] = useState('Edward');

function handleClick() {
setName('Taylor');
setAge(a => a + 1);
// ...

المعاملات

  • next state: القيمة التي تريد أن تكون عليها الحالة. يمكن أن تكون قيمة من أي نوع، ولكن هناك سلوك خاص للدوال.
    • إذا نجحت في اجتياز دالة كـ next state، سيتم التعامل معها كدالة _ تحديث. يجب أن تكون نقية، يجب أن تأخذ الحالة المعلقة كحجة وحيدة، ويجب أن تعيد الحالة التالية. رد الفعل سيضع وظيفة التحديث في طابور ويعيد تقديم المكون الخاص بك. خلال العرض التالي، يقوم React بحساب الحالة التالية من خلال تطبيق كل التحديثات الموجودة في قائمة الانتظار على الحالة السابقة. انظر مثالاً أدناه.

المرجعات

الدوال set ليس لها قيمة ارتجاعية.

التحذيرات

  • الدالة set *** تقوم بتحديث متغير الحالة فقط لـ * تقديم *** التالي. إذا قرأت متغير الحالة بعد استدعاء الدالة set, ستظل تحصل على القيمة القديمة التي كانت على الشاشة قبل استدعائك.

  • إذا كانت القيمة الجديدة التي تقدمها مطابقة للحالة الحالية، كما تحددها مقارنة ‘Object.is’، فإن React سيتخطى *** إعادة تقديم المكون وأبناءه. هذا هو التحسين. على الرغم من أنه في بعض الحالات React قد لا يزال بحاجة إلى استدعاء المكون الخاص بك قبل تخطي الأطفال، فإنه لا ينبغي أن يؤثر على شفرتك.

  • React batches state updates. يقوم بتحديث الشاشة بعد أن يقوم جميع معالجي الأحداث بتشغيل *** وتسمية وظائف “المجموعة” الخاصة بهم. وهذا يمنع إعادة العروض المتعددة خلال حدث واحد. في الحالات النادرة التي تحتاج فيها إلى تحديث الشاشة في وقت سابق، على سبيل المثال للوصول إلى DOM، يمكنك استخدام flushSync.

  • استدعاء وظيفة set أثناء التقديم * مسموح به فقط من داخل مكون التقديم الحالي. سيتجاهل رد الفعل مخرجاته ويحاول على الفور تقديمه مرة أخرى مع الحالة الجديدة. نادرًا ما تكون هناك حاجة إلى هذا النمط، ولكن يمكنك استخدامه للوصول إلى تخزين المعلومات من العروض السابقة *** انظر مثالاً أدناه.

  • في الوضع المقيد، سيستدعي React *** وظيفة التحديث الخاصة بك مرتين *** من أجل مساعدتك في العثور على الشوائب العرضية. هذا سلوك تطويري فقط ولا يؤثر على الإنتاج. إذا كانت وظيفة التحديث الخاصة بك نقية (كما ينبغي أن تكون)، وهذا لا ينبغي أن يؤثر على السلوك. النتيجة من إحدى المكالمات سيتم تجاهلها.


الاستخدام

إضافة حالة إلى مكون

استدعي useState في المستوى الأعلى من المكون الخاص بك لإعلان واحد أو أكثر. state variables.

import { useState } from 'react';

function MyComponent() {
const [age, setAge] = useState(42);
const [name, setName] = useState('Taylor');
// ...

الإتفاقية هي تسمية متغيرات الحالة مثل [something, setSomething] باستخدام array destructuring.

useState إرجاع array يحتوي على عنصرين :

  1. current state لمتغير الحالة تم تعيينها مبدئياً initial state التي قدمتها.
  2. set الدالة التي تسمح لك بتغييرها إلى أي قيمة أخرى كرد فعل للتفاعل.

لتحديث ما يظهر على الشاشة، اتصل بوظيفة الضبط مع بعض الحالات التالية:

function handleClick() {
setName('Robin');
}

React سيقوم بتخزين next state وتقديم المكون مرة أخرى مع القيم الجديدة وتحديث واجهة المستخدم.

Pitfall

استدعاء set الدالة لا يغيرthe current state في الكود المنفذ بالفعل:

function handleClick() {
setName('Robin');
console.log(name); // Still "Taylor"!
}

فهو يؤثر فقط على ما ستعود إليه useState بدءاً من تقديم * التالي.

Basic useState examples

Example 1 of 4:
العداد (number)

رقما .الضغط علي الزر يزيدها state variable count في هذا المثال،يحمل

import { useState } from 'react';

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

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

  return (
    <button onClick={handleClick}>
      You pressed me {count} times
    </button>
  );
}


تحديث الحالة بناء على الحالة السابقة

لنفترض أن الـ age هو 42. يتم استدعاء المعالج (handler) هذا بتنفيذ setAge(age + 1) ثلاث مرات:

function handleClick() {
setAge(age + 1); // setAge(42 + 1)
setAge(age + 1); // setAge(42 + 1)
setAge(age + 1); // setAge(42 + 1)
}

ومع ذلك، بعد النقرة الواحدة، سيكون الـ age 43 فقط بدلاً من 45! هذا يحدث لأن استدعاء دالة الضبط (set) لايحدث تحديثا المتغير الحالي age في الشيفرة القائمة بالفعل. لذا يتحول كل استدعاء setAge(age + 1) إلى setAge(43).

لحل هذه المشكلة يمكنك ان تمرر دالة تحديثية الي setAge بدلا من next stage.

function handleClick() {
setAge(a => a + 1); // setAge(42 => 43)
setAge(a => a + 1); // setAge(43 => 44)
setAge(a => a + 1); // setAge(44 => 45)
}

هنا, a => a + 1 هي دالتك التحديثية. تأخذ الحالة المعلقة وتحسب next state من خلالها

React يضع دوال التحديث في قائمة انتظار (Queue). ثم، خلال العرض (render) التالي، سيتم استدعاؤها بنفس الترتيب:

  1. a => a + 1 ستتلقى 42 كحالة معلقة وستعيد 43 كحالة تالية.
  2. a => a + 1 ستتلقى 43 كحالة معلقة وستعيد 44 كحالة تالية.
  3. a => a + 1 ستتلقى 44 كحالة معلقة وستعيد 45 كحالة تالية. لا توجد تحديثات أخرى معلقة، لذا سيقوم React بتخزين 45 كحالة حالية في النهاية.

بشكل تقليدي، من الشائع تسمية وسيط الحالة المعلقة باستخدام أول حرف من اسم المتغير الحالي، مثل a للـ age. ومع ذلك، يمكنك أيضًا تسميته بمثل prevAge أو أي شيء آخر تجده أوضح.

ربما react تستدعي دالتك التحديثية مرتين في التطوير للتحقق من أنها نقية.

Deep Dive

هل استخدام المستجدات مفضّل دائما؟

قد تسمع توصية بكتابة الشيفرة دائمًا على النحو التالي setAge(a => a + 1) إذا كانت الحالة التي تقوم بتعيينها محسوبة من الحالة السابقة. ليس هناك ضرر في ذلك، ولكنه أيضًا ليس دائمًا ضروريًا.

في معظم الحالات، لا يوجد فرق بين هاتين الطريقتين. تضمن React دائمًا أنه للأحداث المستخدمة بوضوح، مثل النقرات، سيتم تحديث المتغير الحالي age قبل النقرة التالية. وهذا يعني أنه لا يوجد خطر أن يرى معالج النقر حالة age “غير حديثة” في بداية معالج الحدث.

ومع ذلك، إذا قمت بعمليات تحديث متعددة داخل نفس الحدث، يمكن أن تكون الدوال التحديث مفيدة. كما أنها مفيدة إذا كان الوصول إلى المتغير الحالي نفسه غير ملائم (قد تواجه هذا عند تحسين إعادة العرض).

إذا كنت تفضل التناسق على الصيغة البسيطة إلى حد ما، من المعقول دائمًا كتابة دالة التحديث إذا كانت الحالة التي تقوم بتعيينها محسوبة من الحالة السابقة. إذا تم حسابها من الحالة السابقة لمتغير حالة آخر، قد ترغب في دمجهما في كائن واحد و استخدام منظم (reducer).

الفرق بين تمرير حديث وتمرير الولاية التالية مباشرة

Example 1 of 2:
تمرير وظيفة التحديث

في هذا المثال، يتم تمرير دالة التحديث، لذا يعمل زر “+3” بشكل صحيح.

import { useState } from 'react';

export default function Counter() {
  const [age, setAge] = useState(42);

  function increment() {
    setAge(a => a + 1);
  }

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


تحديث الأشياء والمصفوفات في الحالة

بإمكانك وضع كائنات ومصفوفات في الحالة. في React، يُعتبر الحالة “للقراءة فقط”، لذا يجب عليك أن تستبدلها بدلاً من أن تُجفّف (تغيّر) الكائنات الحالية. على سبيل المثال، إذا كان لديك كائن form في الحالة، فلا تُجفّفه:

// 🚩 Don't mutate an object in state like this:
form.firstName = 'Taylor';

بدلاً من ذلك، استبدل الكائن بأكمله عن طريق إنشاء كائن جديد:

// ✅ Replace state with a new object
setForm({
...form,
firstName: 'Taylor'
});

اقرأ تحديث الكائنات في الحالة و تحديث arrays في الحالة to learn more.

أمثلة على objects وarrays في الحالة

Example 1 of 4:
النموذج (كائن)

في هذا المثال، المتغير الحالي form يحتوي على كائن. كل حقل إدخال (input) له معالج تغيير يقوم باستدعاء setForm بالحالة التالية للنموذج بأكمله. بناءً على نحو آمن، يضمن نمط الانتشار { ...form } أن الكائن في الحالة يتم استبداله بدلاً من التغيير في مكوناته.

import { useState } from 'react';

export default function Form() {
  const [form, setForm] = useState({
    firstName: 'Barbara',
    lastName: 'Hepworth',
    email: 'bhepworth@sculpture.com',
  });

  return (
    <>
      <label>
        First name:
        <input
          value={form.firstName}
          onChange={e => {
            setForm({
              ...form,
              firstName: e.target.value
            });
          }}
        />
      </label>
      <label>
        Last name:
        <input
          value={form.lastName}
          onChange={e => {
            setForm({
              ...form,
              lastName: e.target.value
            });
          }}
        />
      </label>
      <label>
        Email:
        <input
          value={form.email}
          onChange={e => {
            setForm({
              ...form,
              email: e.target.value
            });
          }}
        />
      </label>
      <p>
        {form.firstName}{' '}
        {form.lastName}{' '}
        ({form.email})
      </p>
    </>
  );
}


تجنب إعادة الحالة الأولية

React يحفظ الحالة الأولية مرة واحدة ويتجاهلها في العروض التالية.

function TodoList() {
const [todos, setTodos] = useState(createInitialTodos());
// ...

على الرغم من أن نتيجة createInitialTodos()تستخدم فقط للترجمة الأولية، إلا أنك لا تزال تدعو هذه الدالة في كل ترجمة. هذا يمكن أن يكون تبذير إذا كان يخلق صفائف كبيرة أو إجراء حسابات مكلفة.

لحل هذه المشكلة يمكنك تمريرها كوظيفة initializer function الي useState بدلا من :

function TodoList() {
const [todos, setTodos] = useState(createInitialTodos);
// ...

Notice that you’re passing createInitialTodos, which is the function itself, and not createInitialTodos(), which is the result of calling it. If you pass a function to useState, React will only call it during initialization.

ربما React تستدعي initializer الخاص بك مرتين in development to verify that they are pure.

الفرق بين تمرير المبدئ وتمرير الحالة الأولية مباشرة

Example 1 of 2:
تمرير initializer function

هذا المثال يمر دالة البادئ، لذلك يتم تشغيل وظيفة createInitialTodos فقط أثناء التهيئة. وهو لا يعمل عند إعادة عرض المكون كما هو الحال عند الكتابة في الإدخال

import { useState } from 'react';

function createInitialTodos() {
  const initialTodos = [];
  for (let i = 0; i < 50; i++) {
    initialTodos.push({
      id: i,
      text: 'Item ' + (i + 1)
    });
  }
  return initialTodos;
}

export default function TodoList() {
  const [todos, setTodos] = useState(createInitialTodos);
  const [text, setText] = useState('');

  return (
    <>
      <input
        value={text}
        onChange={e => setText(e.target.value)}
      />
      <button onClick={() => {
        setText('');
        setTodos([{
          id: todos.length,
          text: text
        }, ...todos]);
      }}>Add</button>
      <ul>
        {todos.map(item => (
          <li key={item.id}>
            {item.text}
          </li>
        ))}
      </ul>
    </>
  );
}


إعادة ضبط الحالة بمفتاح

غالبًا ما ستواجه السمة key عندما عرض القوائم.ومع ذلك، إنها تخدم أيضًا غرضًا آخر

بإمكانك إعادة ضبط حالة المكوّن عن طريق تمرير مفتاح key مختلف للمكوّن. في هذا المثال، يقوم زر إعادة الضبط بتغيير متغير الحالة version، الذي نمرره كـ key للمكوّن Form. عندما يتغيّر المفتاح، يقوم React بإعادة إنشاء مكوّن Form (وجميع أطفاله) من البداية، لذا تتم إعادة ضبط حالته.

اقرأ preserving and resetting state لتعلم المزيد.

import { useState } from 'react';

export default function App() {
  const [version, setVersion] = useState(0);

  function handleReset() {
    setVersion(version + 1);
  }

  return (
    <>
      <button onClick={handleReset}>Reset</button>
      <Form key={version} />
    </>
  );
}

function Form() {
  const [name, setName] = useState('Taylor');

  return (
    <>
      <input
        value={name}
        onChange={e => setName(e.target.value)}
      />
      <p>Hello, {name}.</p>
    </>
  );
}


تخزين المعلومات من العروض السابقة

عادةً، ستقوم بتحديث الحالة في معالجي الأحداث. ومع ذلك، في الحالات النادرة قد ترغب في ضبط الحالة استجابةً لعملية العرض، على سبيل المثال، قد ترغب في تغيير متغير الحالة عندما تتغير الخاصية (prop).

في معظم الحالات، لن تحتاج إلى ذلك:

في الحالة النادرة التي لا ينطبق أي من هذه الحالات، هناك نمط يمكنك استخدامه لتحديث الحالة استنادًا إلى القيم التي تم عرضها حتى الآن، من خلال استدعاء دالة set أثناء عملية عرض المكون.

إليك مثال. هذا المكون CountLabel يعرض الخاصية count التي يتم تمريرها إليه:

export default function CountLabel({ count }) {
return <h1>{count}</h1>
}

لنفترض أنك تريد أن تعرض ما إذا كان عداد قد زاد أو نقص منذ آخر تغيير. الخاصية count لا تُخبرك بذلك، تحتاج إلى تتبع القيمة السابقة لها. قم بإضافة متغير الحالة prevCount لتتبعها. وأضف متغير حالة آخر يسمى trend لتخزين ما إذا كان العداد قد زاد أو نقص. قارن prevCount مع count وإذا لم تكن متساويين، قم بتحديث كل من prevCount و trend. الآن يمكنك عرض العدد الحالي وكيفية تغييره منذ آخر عرض.

import { useState } from 'react';

export default function CountLabel({ count }) {
  const [prevCount, setPrevCount] = useState(count);
  const [trend, setTrend] = useState(null);
  if (prevCount !== count) {
    setPrevCount(count);
    setTrend(count > prevCount ? 'increasing' : 'decreasing');
  }
  return (
    <>
      <h1>{count}</h1>
      {trend && <p>The count is {trend}</p>}
    </>
  );
}

لاحظ أنه إذا استدعيت دالة ‘set’ أثناء التقديم، يجب أن تكون داخل حالة مثل ‘prevCount!== count’، ويجب أن يكون هناك نداء مثل ‘setPrevCount(count)’ داخل الحالة. وإلا فسيعود جزئك في حلقة حتى ينهار أيضا، يمكنك فقط تحديث حالة مكون تقديم * حاليا على النحو التالي. استدعاء وظيفة ‘set’ لمكون * آخر أثناء التقديم هو خطأ. وأخيرًا، يجب أن تظل المكالمة المضبوطة حالة التحديث دون حدوث طفرة — هذا لا يعني أنه يمكنك كسر قواعد أخرى من الدوال النقية.

يمكن أن يكون هذا النمط من الصعب فهمه وعادة ما يكون من الأفضل تجنبه. ومع ذلك، فإنه أفضل من تحديث الحالة في التأثير. عندما تقوم باستدعاء وظيفة set أثناء التقريب، ستقوم React بإعادة تقديم ذلك المكون مباشرة بعد خروج المكون الخاص بك مع عبارة return وقبل تقديم الأطفال. بهذه الطريقة، لا يحتاج الأطفال إلى التوليد مرتين. وسيستمر تنفيذ بقية وظيفة المكون الخاصة بك (وسيتم التخلص من النتيجة). وإذا كانت حالتك دون كل مكالمات هوك، يمكنك ان تضيف return مبكرا ؛ لتعود الى العرض في وقت ابكر.


استكشاف الأخطاء وإصلاحها

لقد قمت بتحديث الحالة، ولكن عندما أقوم بتسجيل البيانات، يعطيني القيمة القديمة.

استدعاء دالة set لا يقوم بتغيير الحالة في الكود الحالي:

function handleClick() {
console.log(count); // 0

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

setTimeout(() => {
console.log(count); // Also 0!
}, 5000);
}

ذلك بسبب الحالات تتصرف كصورة فوتوغرافية. تحديث الحالة يُطلب عرضًا آخر بقيمة حالة جديدة، ولكنه لا يؤثر على متغير count في جافا سكريبت في معالج الأحداث الذي يعمل بالفعل.

إذا كنت بحاجة إلى استخدام الحالة التالية، يمكنك حفظها في متغير قبل تمريرها إلى دالة set:

const nextCount = count + 1;
setCount(nextCount);

console.log(count); // 0
console.log(nextCount); // 1

لقد قمت بتحديث الحالة، ولكن الشاشة لا تُحدّث؟

React سوف تتجاهل تحديثك إذا كانت الحالة التالية مساوية للحالة السابقة , كما يتم تحديدها بواسطة Object.is عملية المقارنة. يحدث ذلك عادةً عندما تقوم بتغيير كائن أو مصفوفة في الحالة مباشرةً:

obj.x = 10; // 🚩 Wrong: mutating existing object
setObj(obj); // 🚩 Doesn't do anything

لقد قمت بتغيير الكائن obj الموجود وقمت بتمريره مرة أخرى إلى setObj، لذا قام React بتجاهل التحديث. لتصحيح هذا، يجب عليك التأكد دائمًا من أنك تقوم بإنشاء نسخة جديدة من الكائن قبل تمريره إلى setObj _بدلاً من تعديلها، قم بإستبدال الكائنات والمصفوفات في الحالة.:

// ✅ Correct: creating a new object
setObj({
...obj,
x: 10
});

أنت تواجه خطأ “عدد كبير جدًا من عمليات إعادة العرض”.

قد تحصل على خطأ يقول: “عدد كبير جدًا من عمليات إعادة العرض. تحدّ React عدد عمليات العرض لمنع الحلقة اللانهائية.” عادةً ما يعني ذلك أنك تقوم بضبط الحالة بشكل غير مشروط أثناء عملية العرض، لذلك يدخل المكون في حلقة: عرض، ضبط الحالة (الذي يسبب عملية عرض جديدة)، عرض، ضبط الحالة (الذي يسبب عملية عرض جديدة)، وهكذا. في كثير من الأحيان، يتسبب هذا في حدوث خطأ أثناء تحديد معالج الأحداث:

// 🚩 Wrong: calls the handler during render
return <button onClick={handleClick()}>Click me</button>

// ✅ Correct: passes down the event handler
return <button onClick={handleClick}>Click me</button>

// ✅ Correct: passes down an inline function
return <button onClick={(e) => handleClick(e)}>Click me</button>

إذا لم تتمكن من العثور على سبب هذا الخطأ، انقر على السهم المجاور للخطأ في وحدة التحكم وابحث في مكدس الجافاسكريبت للعثور على استدعاء دالة set المحدد الذي يسبب الخطأ.


مُبدّل البداية (initializer) أو دالة التحديث (updater) تعمل مرتين.

في الوضع الصارم, سوف تستدعي Reactfبعص الدوال مرتين بدلاً من مرة واحدة

function TodoList() {
// This component function will run twice for every render.

const [todos, setTodos] = useState(() => {
// This initializer function will run twice during initialization.
return createTodos();
});

function handleClick() {
setTodos(prevTodos => {
// This updater function will run twice for every click.
return [...prevTodos, createTodo()];
});
}
// ...

هذا أمر متوقع ولا يجب أن يؤذي الكود الخاص بك

هذا development-only السلوك يساعدك في الحفاظ على بقاء المكونات نقية. React يستخدم نتيجة إحدى الاستدعاءات ويتجاهل نتيجة الاستدعاء الأخرى. طالما كانت دوال مكونك، ومبدّل البداية، ومبدّل التحديث نقية، فإن هذا لن يؤثر على منطقك. ومع ذلك، إذا كانت هذه الدوال غير نقية عن طريق الخطأ، فإن هذا يساعدك في اكتشاف الأخطاء.

على سبيل المثال، دالة مبدل التحديث غير النقية تقوم بتعديل مصفوفة في الحالة:

setTodos(prevTodos => {
// 🚩 Mistake: mutating state
prevTodos.push(createTodo());
});

نظرًا لأن React تستدعي دالة مبدل التحديث مرتين، سترى أن المهمة Todo تمت إضافتها مرتين، وبالتالي ستعلم أن هناك خطأً. في هذا المثال، يمكنك تصحيح الخطأ عن طريق: استبدال المصفوفة بدلاً من تعديلها.:

setTodos(prevTodos => {
// ✅ Correct: replacing with new state
return [...prevTodos, createTodo()];
});

الآن بما أن دالة مبدل التحديث هذه نقية، فإن استدعائها مرة إضافية لا يؤثر في السلوك. وهذا هو السبب في أن استدعاء React لها مرتين يساعدك في اكتشاف الأخطاء. فقط دوال المكون، ومبدل البداية، ومبدل التحديث يجب أن تكون نقية. لا يجب أن تكون معالجات الأحداث نقية، لذلك لن يقوم React أبدًا باستدعاء معالجات الأحداث الخاصة بك مرتين.

اقرأ الحفاظ على نقاء المكوناتلتعلم المزيد.


أنا أحاول تعيين الحالة إلى دالة، ولكنها تتم استدعاؤها بدلاً من ذلك

لا يمكنك وضع دالة في الحالة بهذه الطريقة:

const [fn, setFn] = useState(someFunction);

function handleClick() {
setFn(someOtherFunction);
}

نظرًا لأنك تمرر دالة، يفترض React أن someFunction تمثلدالة المبدل الأولي, وأن someOtherFunction هي دالة المبدل, لذلك يحاول استدعاؤها وتخزين النتيجة. لتخزين الوظيفة فعلياً، يجب وضع () => قبلهما في كلا الحالتين. بذلك سيقوم React بتخزين الوظائف التي تمررها.

const [fn, setFn] = useState(() => someFunction);

function handleClick() {
setFn(() => someOtherFunction);
}