React: يحتوي React Hook useEffect على تبعية مفقودة: 'xxx'؟

تم إنشاؤها على ١٢ يونيو ٢٠١٩  ·  69تعليقات  ·  مصدر: facebook/react

مرحبًا ، أقوم ببحث في React Hook مؤخرًا ، إنه رائع.

لكن لدي مشكلة ، لم أجد إجابة مناسبة في وثائق React Hook و google لحل مشكلتي.

عندما استخدمت دالة في useEffect ومكوِّن دالة معًا ، واجهت تحذيرًا بأنني لم أحدد تبعية في useEffect ، كما هو موضح أدناه:

image

هل هناك طريقة لحل مشكلتي؟ لقد فكرت في ذلك لفترة طويلة.

ما هو السلوك الحالي؟

React Hook useEffect has a missing dependency: 'setCenterPosition'. Either include it or remove the dependency array. (react-hooks/exhaustive-deps)

ميني ريبرو في كوداندبوكس:
https://codesandbox.io/s/trusting-kowalevski-oet4b

اي حل شكرا.

الشفرة

function App() {
  const [elePositionArr, setElePositionArr] = useState([
    { left: 0, top: 0 },
    { left: 0, top: 0 },
    { left: 0, top: 0 }
  ]);
  const stageRef = useRef(null);
  const Stage = useRef({ w: 0, h: 0 });
  const currentIndex = useRef(0);

  useEffect(() => {
    // Record the size of the stage
    const stageW = stageRef.current.scrollWidth;
    const stageH = stageRef.current.scrollHeight;

    Stage.current = { w: stageW, h: stageH };

    const index = Math.floor(Math.random() * 3);
    currentIndex.current = index;
    setCenterPosition(index);
  }, []);

  // Centering a block element
  function setCenterPosition(index) {
    let cacheEle = elePositionArr;
    // calc center postion
    const centerOfLeft = Stage.current.w / 2 - 25;
    const centerOfTop = Stage.current.h / 2 - 25;

    cacheEle = cacheEle.map((item, i) => {
      const randomWNum = Math.floor(Math.random() * Stage.current.w) - 50;
      const randomHNum = Math.floor(Math.random() * Stage.current.h) - 50;
      const randomLeft = randomWNum <= 50 ? 50 : randomWNum;
      const randomTop = randomHNum <= 50 ? 50 : randomHNum;
      let newItem;

      if (index === i) {
        newItem = { left: centerOfLeft, top: centerOfTop };
      } else {
        newItem = { left: randomLeft, top: randomTop };
      }

      return newItem;
    });

    setElePositionArr(cacheEle);
  }

  function handleClickLi(index) {
    if (currentIndex.current !== index) {
      setCenterPosition(index);
      currentIndex.current = index;
    }
  }

  return (
    <div className="container">
      <div className="stage" ref={stageRef}>
        {elePositionArr.map((item, index) => (
          <div className="ele" key={index} style={item}>
            {index}
          </div>
        ))}
      </div>
      <ul className="nav">
        {elePositionArr.map((item, index) => (
          <li
            className={currentIndex.current === index ? "active-li" : ""}
            onClick={() => {
              handleClickLi(index);
            }}
            key={"li" + index}
          >
            {index}
          </li>
        ))}
      </ul>
    </div>
  );
}

التعليق الأكثر فائدة

عندما يواجه الآلاف من مطوري البرامج نفس المشكلة ويغلق فريق مطوري React الموضوع ويتجاهل الجميع:
8d6

ال 69 كومينتر

وهذا ينبغي أن أجيب على سؤالك:

https://reactjs.org/docs/hooks-faq.html#is -it-safe-to-omit-function-from-the-list-of-التبعيات

وهذا ينبغي أن أجيب على سؤالك:

https://reactjs.org/docs/hooks-faq.html#is -it-safe-to-omit-function-from-the-list-of-التبعيات

تضمين التغريدة
لم تحل مشكلتي ، مشكلتي أكثر خصوصية ، فإن دالات التشغيل الخاصة بي ترغب في أن يتم تشغيلها على componentDidMount و handleClick ، ​​لكن وظيفة React Hook لا تفي بمتطلباتي ويظهر تحذير.

سؤالي هو: React Hook لا يمكنه استدعاء دالة في useEffect ومكوِّن الوظيفة لعملية setState?

ترك مفتوحًا حتى نتمكن من الرد على السؤال الثاني.

لدي نفس تحذير ESLint ولكن في حالتي أريد إجراء مكالمة غير متزامنة عند تركيب المكون الخاص بي.

const ManageTagsModalBody: React.FC<IProps> = ({ children, getTags }) => {
  useEffect(() => {
    getTags();
  }, []);

  return <div>{children}</div>;
};
Line 12:  React Hook useEffect has a missing dependency: 'getTags'. Either include it or remove the dependency array. If 'getTags' changes too often, find the parent component that defines it and wrap that definition in useCallback  react-hooks/exhaustive-deps 

لا يعتمد ManageTagsModalBody على أي بيانات يتم استخدامه فقط كغلاف لتحميل البيانات في أي وقت يتم فيه عرض المكون. تجدر الإشارة إلى أن المكون children يستخدم البيانات التي جلبها getTags .

لست متأكدًا مما يجب إضافته إلى قائمة التبعيات.

أنا مهتم بالحصول على شرح أيضًا.
React Hook useEffect له تبعية مفقودة: "إرسال".

  useEffect(() => {
    axios.get('http://localhost:8000/api/future-registrations')
      .then((result) => {
        dispatch(initRegistrationsAction(result.data));
      });
  }, []);

نفس المشكلة هنا. حكم غريب.

كذلك هنا. بهذه البساطة في https://github.com/facebook/react/issues/15865#issuecomment -506503377:

  useEffect(() => {
    dispatch(fetchPosts());
  }, []);

هل هناك طريقة لإلغاء هذا التحذير؟

كما هو مقترح في رسالة التحذير ، يمكنك فعل ذلك

const initFetch = useCallback(() => {
    dispatch(fetchPosts());
  }, [dispatch]);

  useEffect(() => {
    initFetch();
  }, [initFetch]);

fayway ثم عند تغيير قيمة initFetch و dispatch ، سيتم تنفيذ رد نداء useEffect.
يريد تنفيذ رد الاتصال مرة واحدة

shkyung في حالتي، سوف initFetch لن يغير سبب (مخزن) إرسال لا أحد

ربما يمكن أن يكون مثل هذا

const setCenterPosition = useRef(null)
setCenterPosition.current = useCallback( ()=>{} ,[deps])

effect(()=>{ setCenterPosition.current() },[setCenterPosition,otherDeps])

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

لديك نفس المشكلة. أريد فقط أن يتم تشغيل عملية الجلب الخاصة بي على componentDidMount. تؤدي إضافة التبعية إلى المصفوفة إلى ضرب نقطة النهاية بشكل متكرر.

React Hook useEffect له تبعية مفقودة: "إرسال".

const [state, dispatch] = useReducer(reducer, initialState);
const { count, step } = state;

useEffect(() => {
  const id = setInterval(() => {
    dispatch({ type: 'tick' }); // Instead of setCount(c => c + step);
  }, 1000);
  return () => clearInterval(id);
}, [dispatch]);

يبدو أن هذه حالة استخدام شائعة إلى حد ما - حالة صادفتها في مشروعي الحالي.

تريد تشغيل خطاف تأثير مرة واحدة فقط ، ولكن هناك تبعية ، على الرغم من أنك لا تهتم إلا بحالة ذلك عند بدء التشغيل. تستخدم حاليا
// eslint-disable-next-line react-hooks/exhaustive-deps ،
لإيقاف تشغيل قاعدة الفحص ولكن سيكون من الجيد ألا تضطر إلى ذلك في هذه الحالة.

يبدو أن هذه حالة استخدام شائعة إلى حد ما - حالة صادفتها في مشروعي الحالي.

تريد تشغيل خطاف تأثير مرة واحدة فقط ، ولكن هناك تبعية ، على الرغم من أنك لا تهتم إلا بحالة ذلك عند بدء التشغيل. تستخدم حاليا
// eslint-disable-next-line react-hooks/exhaustive-deps ،
لإيقاف تشغيل قاعدة الفحص ولكن سيكون من الجيد ألا تضطر إلى ذلك في هذه الحالة.

إغلاق لينت هو مجرد حل مؤقت ، ومفتاح هذه المشكلة لا يكفي لفهم الخطاف.

نفس المشكلة هنا. أردت فقط إطلاق دالة داخل useEffect () مرة واحدة ، حيث أن [] كمعامل ثانٍ يفعل ما أريد ، لكنه يستمر في إعطاء هذا التحذير.

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

أود أن أضع سنتي هنا. على وجه الخصوص مع استخدام Axios لإلغاء طلب الشبكة. سيتم إنشاء مشكلة منفصلة إذا لزم الأمر ولكن شعرت أن هذه المشكلة أثرت بشكل مباشر على نفسي. لذا فإن خطافي Api هو كما يلي -

import axios, { AxiosInstance } from "axios";
import axiosRetry from "axios-retry";
import { FetchEnv } from "../../utilities";
import { useStorage } from "../useStorage";

export const useApi = ({ isAuth = false, retries = 3 } = {}) => {
  const cancelToken = axios.CancelToken.source();
  const { getItem } = useStorage();

  const getBaseUrl = () => {
    return FetchEnv({
      defaultValue: "http://api.example.com",
      key: "API_URI"
    });
  };

  const authorizedClient = (client: AxiosInstance) => {
    const session = getItem("SESSION", "sessionStorage");
    const hasAccessToken = Boolean(session.tokens.accessToken);

    if (isAuth && !hasAccessToken) {
      console.error("No access token found to initiate authorized request.");
      return client;
    } else {
      client.defaults.headers[
        "Authorization"
      ] = `Bearer ${session.tokens.accessToken}`;
      return client;
    }
  };

  const buildFetch = (): AxiosInstance => {
    const client = axios.create({
      baseURL: getBaseUrl(),
      cancelToken: cancelToken.token
    });
    axiosRetry(client, { retries });
    return isAuth ? authorizedClient(client) : client;
  };

  return {
    cancelRequest: cancelToken.cancel,
    fetch: buildFetch()
  };
};

لاستخدام هذا الخطاف داخل أحد المكونات ، ما عليك سوى تحديده على النحو التالي ، ثم يمكن استخدامه لإجراء مكالمات مصدق عليها وغير مصادق عليها إما على mount أو داخل useEffect أو كجزء من معالج الحدث ، وما إلى ذلك. التي تم إقرانها بمثيل axios "الجلب" المتعلق بهذا المكون.

const { cancelRequest, fetch } = useApi();

إذا تم فصل هذا المكون لأي سبب من الأسباب ، فسيتم استدعاء ما يلي:

  useEffect(() => {
    return () => {
      cancelRequest("Auth network request cancelled");
    };
  }, []);

الآن يعمل بشكل مثالي في الوقت الحاضر. ومع ذلك ، فإن التحذير ، عند تطبيقه (وضع إلغاء الطلب باعتباره تبعية useEffect) ، يلغي فورًا طلب الشبكة عند استدعاء طريقة الجلب. أي نصيحة ستكون موضع تقدير كبير ، ولكن يبدو أن الحل الوحيد في الوقت الحالي هو تعطيل ts-lint هذا المضي قدمًا ...

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

وأدى لي أن أتساءل عما إذا كان في @ Stoner609 الصورة سبيل المثال فقط فوق هذا، يجب أن يكون رمز توقيت في ربط useCallback؟ لا يزال من الغريب أن يكون لها وظيفة (والتي يجب أن تكون ثابتة) باعتبارها تبعية.

أعتقد أن هذه الحالة يجب أن تكون نوعًا من الاستثناء

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

  const InitialPropA= useRef(propA);
  useEffect(() => {
    myFunction(InitialPropA.current);
  }, [myFunction, InitialPropA]);

كما هو مقترح في رسالة التحذير ، يمكنك فعل ذلك

const initFetch = useCallback(() => {
    dispatch(fetchPosts());
  }, [dispatch]);

  useEffect(() => {
    initFetch();
  }, [initFetch]);

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

أود أن أعرف بالضبط ماذا ولماذا يحدث في هذه المجموعة من الغموض :)

كما هو مقترح في رسالة التحذير ، يمكنك فعل ذلك

const initFetch = useCallback(() => {
    dispatch(fetchPosts());
  }, [dispatch]);

  useEffect(() => {
    initFetch();
  }, [initFetch]);

قد يؤدي هذا أيضًا إلى حدوث تسرب للذاكرة في حالة وجود شيء مثل واجهة برمجة التطبيقات (API) ، فسيؤدي ذلك إلى إجراء المكالمة في حلقة لا نهائية.

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

تواجه نفس الخطأ -

React Hook useEffect له تبعية مفقودة: "props". ومع ذلك ، ستتغير "الدعائم" عند تغيير أي عنصر ، لذا فإن الإصلاح المفضل هو تدمير كائن "الدعائم" خارج استدعاء useEffect والإشارة إلى تلك الدعائم المحددة داخل use

الشفرة -

  useEffect(() => {
    props.dispatch(searchMediaAction("rain"));
  }, []);

luojinghui : اسمحوا لي أن أعرف إذا قمت بحل خطأ النسالة

نفس الخطأ

نفس المشكلة. أريد تقليد سلوك componentDidMount ؛ لست مهتمًا بالتحذير ؛ لا أريد إعادة تشغيل الخطاف عندما يتغير أي شيء

أقترح عدم إظهار هذا التحذير عندما تكون الوسيطة الثانية لـ useEffect() هي [] ، b / c في هذه الحالة يعلم المطور أن هذا التأثير لن يتم تشغيله إلا مرة واحدة ، وبالتالي _ يريد_ استخدامه قيم الخاصية الأولية ولا تهتم إذا تغيرت الخاصية في العروض اللاحقة.

حالة 1:
إذا أردنا تشغيل الوظيفة عند التهيئة وكذلك عندما تتغير قيمة المعلمات المحددة (كما يوحي تحذير النسالة) ، فإننا نمرر هذه المعلمات إلى المصفوفة.

الحالة 2:
إذا أردنا تشغيل الوظيفة

في الحالة 2 ، نستمع بشكل أساسي إلى حدث componentDidMount وفقًا لمواصفات توثيق React Hook. خطأ lint غير متوافق مع وثائق React Hook وتوقعات المطور.

لماذا هذا مغلق؟

أي حلول؟

تضمين التغريدة

بعد تجربة مجموعة من الاقتراحات المختلفة ، هذا ما نجح معي في النهاية. فضلت عدم استخدام eslint-disable ، أثناء محاولة الحفاظ على الكود بسيطًا نسبيًا للمبتدئين. يسمح لك هذا الأسلوب بتمرير وظيفة الإرسال الخاصة بك دون استدعائها داخل useCallback. أتمنى أن يساعدك هذا.

`` جافا سكريبت
// ... داخل مكون الوظيفة
const {dispatchFunc} = customHook () ،
const memoizeDispatchFunc = useCallback (dispatchFunc، []) ،

useEffect (() => {
memoizeDispatchFunc () ،
} ، [memoizeDispatchFunc]) ؛
""

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

useEffect(()=>{ myFunc(); } )

robthedev حل
يمكننا حتى تبسيط الكود إذا استخدمنا redux:

const dispatch = useDispatch();

// redux can guarantee that the dispatch function will not change between renders.
// so we don't need to wrap it with useCallback for now.
useEffect(() => {
  dispatch(actions());
}, [dispatch]);

هذا المقال يساعدني كثيرا.

لا يكمن حل هذه المشكلة في إزالة التبعية ، بل يمكننا بدلاً من ذلك رفع الوظائف التي لا تحتاج إلى دعائم أو حالة خارج المكون أو لفها في useCallback حيث يتم تعريفها.

تضمين التغريدة

بعد تجربة مجموعة من الاقتراحات المختلفة ، هذا ما نجح معي في النهاية. فضلت عدم استخدام eslint-disable ، أثناء محاولة الحفاظ على الكود بسيطًا نسبيًا للمبتدئين. يسمح لك هذا الأسلوب بتمرير وظيفة الإرسال الخاصة بك دون استدعائها داخل useCallback. أتمنى أن يساعدك هذا.

// ... inside function component
const { dispatchFunc } = customHook();
const memoizeDispatchFunc = useCallback(dispatchFunc, []);

useEffect(() => {
  memoizeDispatchFunc();
}, [memoizeDispatchFunc]);

معي لا يعمل المثال أعلاه.

احصل على هذا الخطأ:
TypeError: Cannot destructure property 'dispatchFunc' of 'componentDidMount(...)' as it is undefined.

@ رد فعل فريق: سعيد رمز Boilerplate. :) هل يمكن أن تكون منطقية وقابلة للقراءة مرة أخرى ... يجب أن تكون الأحداث سهلة الاستخدام ... دون الحاجة إلى كتابة أكثر من 5 أسطر من المنطق لاستدعاء دالة.

بالنسبة لي ، ظهر الخطأ في الحالة التالية:

  useEffect(() => {
    props.getTasks()
  }, [])

لقد قمت بتصحيحه على النحو التالي:

const { getTasks } = props
  useEffect(() => {
    getTasks()
  }, [getTasks])

عندما يواجه الآلاف من مطوري البرامج نفس المشكلة ويغلق فريق مطوري React الموضوع ويتجاهل الجميع:
8d6

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

function hydrate( _state, _errors=false) {
    console.log('hydrate()');
    setState({...state,..._state});
    if(_errors){
        setErrors({...errors,..._errors});
    }
}

من المتوقع أن يستخدم المستخدم هذا مع useEffect() لترطيب حالتهم كما يلي:

useEffect(()=>{
    hydrate({
        name:'Garrett',
        email:'[email protected]',
        newsletter: 'yes'
    });
},[hydrate]); //unfortunately, this causes an infinite render, because hydrate will always change

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

const hydrate = useCallback(( _state, _errors=false )=> {
    console.log('hydrate()');
    setState({...state,..._state});
    if(_errors){
        setErrors({...errors,..._errors});
    }
},[]);

هل يمكن لأي شخص تأكيد ما إذا كان هذا صحيحًا أم لا ، فإن useCallback يمنع hydrate من التحول في العرض ، وبالتالي من الأفضل التفاف كل هذه الوظائف في useCallback للحصول على أداء أفضل ؟

redux can guarantee that the dispatch function will not change between renders.

هل انت متاكد من ذلك؟
رابط إلى المستندات حيث تقول ذلك من فضلك.

تحقق من https://overreacted.io/a-complete-guide-to-useeffect/#decoupling -updates-from-Actions لمزيد من التفاصيل أو يمكنك التحقق من التعليمات البرمجية لـ

هنا أشير فقط إلى ما قاله دان:

الإجابة هي أن React تضمن أن تكون وظيفة الإرسال ثابتة طوال عمر المكون. لذا فإن المثال أعلاه لا يحتاج أبدًا إلى إعادة الاشتراك في الفترة الزمنية.

يضمن أن تكون وظيفة الإرسال ثابتة

رائع شكرا!

عندما يواجه الآلاف من مطوري البرامج نفس المشكلة ويغلق فريق مطوري React الموضوع ويتجاهل الجميع:
8d6

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

حسنًا ، ليس هناك الكثير ليقوله ، بغض النظر عن حقيقة أن الخيط مغلق سمه.

يواجه نفس المشكلة!

المحلول،
(هذا عمل معي):

const onInit = function(){ 
    console.log('initiated', Date.now());
}

useEffect(onInit, []);

أفضل أن يتم إصلاح المشكلة من جانب الفحص ، ولكن مهلا ...

@ ra30r حل لطيف ولكن أتساءل عما إذا كان يمكن أن يخلق آثارًا جانبية؟ : التفكير:

لا شيء حتى الآن؟ 😔

كانت لدي حالة تعلمت فيها تشغيل أخطاء التحقق من صحة النموذج من دورة تدريبية في Udemy.

أدى هذا إلى تشغيل التبعية المفقودة "إرسال" ، ولكنها لا تزال تعمل:

  useEffect(() => {
    if (state.business_name.value) {
      const delay = setTimeout(() => dispatch({ type: "businessNameAfterDelay" }), 1000)
      return () => clearTimeout(delay)
    }
  }, [state.business_name.value])

باستخدام مثال @ ra30r ، قمت بتغييره إلى هذا لمسح الخطأ:

  const businessNameAfterDelay = function () {
    if (state.business_name.value) {
      const delay = setTimeout(() => dispatch({ type: "businessNameAfterDelay" }), 1000)
      return () => clearTimeout(delay)
    }
  }

  useEffect(businessNameAfterDelay, [state.business_name.value])

لماذا هذا مغلق؟

أعتقد أنه تم تقديم إجابة في مكان ما .. لول .. على أي حال .. الحل هو أن تفعل مثل هذا:
useEffect(() => { dispatch(); }, [dispatch]);

أتمنى أن يساعدك هذا!!

لماذا هذا مغلق؟

أعتقد أنه تم تقديم إجابة في مكان ما .. لول .. على أي حال .. الحل هو أن تفعل مثل هذا:
useEffect(() => { dispatch(); }, [dispatch]);

أتمنى أن يساعدك هذا!!

نعم ، هذا الحل يعمل ، قال @ kennylbj هنا منذ بعض الوقت.
لماذا تم إغلاق القضية؟ هناك الميمات هنا أيضًا حول هذا الموضوع ... xd

مشكلتي نوعًا ما مثل هذا (نموذج رمز):

  const [userStatus, setUserStatus]: any = React.useState([]);
  const [userData, setUserData]: any = React.useState([]);

  useEffect(() => {
    setUserStatus(!userStatus);
    return () => {};
  }, [userData]);

لذا كما هو الحال في الكود ، فأنت تريد تغيير userStatus عندما يكون هناك تغيير في userData وفي هذه الحالة إذا كنت تريد التحقق من userStatus فعليك إضافتها إلى deps:

  const [userStatus, setUserStatus]: any = React.useState([]);
  const [userData, setUserData]: any = React.useState([]);

  useEffect(() => {
    setUserStatus(!userStatus);
    return () => {};
  }, [userData, userStatus]);

في هذا السيناريو ستكون حلقة لا تنتهي أبدًا

تضمين التغريدة
يمكنك استخدام أسلوب رد الاتصال الخاص بـ useState لتجنب إدخال متغير حالة المستخدم في مصفوفة التبعيات الخاصة بـ useEffect.

 useEffect(() => {
    setUserStatus(prevState => !prevState);
    return () => {};
  }, [userData]);

وهذا ما يسمى بالتحديثات الوظيفية .

الحل -> فقط أضف الإرسال في الأخير للتبعية
React Hook useEffect له تبعية مفقودة: "إرسال".

  useEffect(() => {
    axios.get('http://localhost:8000/api/future-registrations')
      .then((result) => {
        dispatch(initRegistrationsAction(result.data));
      });
**  }, [dispatch]);**

@ kennylbj هذا أمر جيد عندما تتعامل مع ولاية واحدة ، سيناريو عملي الفعلي هو الدعائم. أنا أرسل دعائم من الوالدين وتغيرت مرتين ، لذا فإن تأثير المستخدم يستدعي مرتين ولكني أقوم بتشغيل مستمع بداخله وسوف يستمع مرتين.

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

إذا كنت لا تزال لا تريد استدعاء المستمع مرتين ، أعتقد أنه يجب عليك الاهتمام أكثر بالدعائم التي تم تمريرها إليه والتأكد من عدم تغييرها أثناء عمليات العرض.

@ kennylbj حسنًا ، أقوم
image
أعتقد أنني يجب أن أتعامل مع هذا من فئة المستمع ،

يبدو أنه تم استدعاء المستمع مرتين حتى لو كان معرف المقبس هو نفسه.

لا أعتقد أن هذا سيحدث إذا اجتمع الموقف التالي:

ts // call useEffect if and only if sockeId changed. useEffect(() => { const unregister = register(socketId); return () => unregister(socketId); }, [socketId])

هل هناك أي متغيرات أخرى في مصفوفة التبعيات تغيرت أثناء عمليات التصيير المختلفة وتسبب هذا السلوك؟

نعم 3 تبعيات ، لكنني اكتشفت ذلك بطريقة مختلفة

بين

كما هو مقترح في رسالة التحذير ، يمكنك فعل ذلك

const initFetch = useCallback(() => {
    dispatch(fetchPosts());
  }, [dispatch]);

  useEffect(() => {
    initFetch();
  }, [initFetch]);

واو , 非常 感谢 你 🙏

🚀 أدناه مقتطف الشفرة يعمل جيدًا بالنسبة لي

على المكون جبل

const onInit = () => getUsers()
useEffect(onInit, [])

على تغيير المعلمة

const onInit = () => getUser(id)
useEffect(onInit, [id])

أفضل حل بديل: رد فعل الخطافات / استنفاد-deps: "إيقاف"
لم أجد أبدًا ميزة eslint هذه مفيدة. أبدا.

🚀 أدناه مقتطف الشفرة يعمل جيدًا بالنسبة لي

على المكون جبل

const onInit = () => getUsers()
useEffect(onInit, [])

على تغيير المعلمة

const onInit = () => getUser(id)
useEffect(onInit, [id])

عمل جيد.

لا أعتقد أن مستندات رد الفعل تغطي تمامًا حالة استخدام luojinghui ، وهذا أيضًا هو نفسه الذي

لدينا عدة طرق لاستدعاء وظيفة معينة ، مثل: setCenterPosition() . يمكن استدعاؤه من خلال مراقبة تغيير الحالة (التوصيل عبر useEffect ) ، معالج النقرات (يسمى مباشرة) ، إلخ.

ورد الفعل يقترح

هذا هو السبب في أنك سترغب عادةً في الإعلان عن الوظائف التي يحتاجها تأثير داخلها

ولكن عادةً في أمثلة العالم الواقعي ، نحتاج إلى إعادة استخدام الدوال مثلما نفعل عادةً مع طرق المثيل في مكون فئة ( this.setCenterPosition(...) ) ، وبدأت أتساءل عما إذا كانت الخطافات جيدة بالفعل للميزات الكاملة ، مكونات معقدة.

لست متأكدًا بالفعل ، لكن ربما يكون الحل هو useCallback

const setCenterPosition = useCallback(() => {
  ...
}, [Stage, elePositionArr, setElePositionArr]);

useEffect() => {
  ...
}, [stageRef, Stage, currentIndex, setCenterPosition]);

... لكن هذا مقزز نوعًا ما بالنسبة لي ، وآمل أن تكون هناك طريقة أنظف. ربما gaearon يمكن أن تؤكد؟

تواجه نفس المشكلة يمكنني تعطيل تحذير bu باستخدام هذا السطر في نهاية useEffect // eslint-disable-next-line react-hooks/exhaustive-deps لكني لا أريد استخدامه

هذا هو الكود الخاص بي

`const [items، setItems] = useState ([
{
الاسم: "اختبار 1" ،
المعرف: 1
} ،
{
الاسم: "الاختبار 2" ،
المعرف: 2
} ،
{
الاسم: "اختبار 3" ،
المعرف: 3
} ،
{
الاسم: "اختبار 4" ،
المعرف: 4
} ،
{
الاسم: "اختبار 5" ،
المعرف: 5
}
]) ؛

useEffect (() => {
const الفاصل الزمني = setInterval (() => {
setItems (shuffleArray (العناصر)) ؛
} ، 1000) ؛
العودة () => {
clearInterval (الفاصل الزمني) ؛
} ؛
// eslint-disable-next-line-response-hooks / exhaustive-deps
} ، []) ؛

كان الحل الخاص بي لهذه المشكلة هو التوقف عن استخدام خطافات React لهذه الحالات. إذا كان المكون يحتاج إلى الكثير من منطق الحالة وأحداث دورة الحياة مثل componentDidMount بهذا السوء ، فما عليك سوى استخدام مكون فئة وحفظ نفسك من الصداع. مكونات الفئة جيدة تمامًا ، وإذا أثبت هذا الخيط أي شيء ، فهو أن React Hooks ليست جاهزة لاستبدالها تمامًا عندما تكون هناك حاجة إلى منطق الحالة المعقدة أو أحداث دورة الحياة (كما أنها لا تمنح أي ميزة في معظم هذه الحالات - هل الكود الخاص بك _ حقًا_ هذا أفضل بكثير لاستخدام خطافات React؟).

سأقصر استخدامي الخاص لـ React Hooks على تلك البسيطة مثل useState لتعيين أعلام منطقية وهذا النوع من الأشياء. إذا أصبح أحد المكونات معقدًا بما يكفي ليحتاج إلى useEffect فأنا أتعامل معه على أنه علامة على أنه ربما يكون مكون الفصل مناسبًا بشكل أفضل.

(تم تعديله من أجل الوضوح).

هذا هو الحل الآن:

const mounted = () => {
  dispatch(something());
}

useEffect(mounted, []);

شكرا @ ra30r رد فعل / قضايا / 15865 # issuecomment-651254164

هل كانت هذه الصفحة مفيدة؟
0 / 5 - 0 التقييمات