প্রতিক্রিয়া হুকগুলির একটি আনমাউন্টযুক্ত অংশে ক্লিনআপ মেমরি ফাঁস হয়


19

আমি প্রতিক্রিয়া ব্যবহার করে নতুন, তাই এটি অর্জন করা সত্যিই সহজ তবে আমি কিছু গবেষণা করেও নিজের দ্বারা এটি বের করতে পারি না। যদি খুব বোবা হয় তবে আমাকে ক্ষমা করুন।

প্রসঙ্গ

আমি লারভেল (ব্যাকএন্ড) এবং প্রতিক্রিয়া (ফ্রন্ট-এন্ড) অ্যাডাপ্টারগুলির সাথে Inertia.js ব্যবহার করছি । আপনি যদি জড়তা না জানেন তবে এটি মূলত:

জড়তা.জেএস আপনাকে দ্রুত ক্লাসিক সার্ভার-সাইড রাউটিং এবং কন্ট্রোলার ব্যবহার করে আধুনিক একক পৃষ্ঠার প্রতিক্রিয়া, ভ্যু এবং স্বেল্ট অ্যাপ্লিকেশনগুলি তৈরি করতে দেয়।

সমস্যা

আমি একটি সাধারণ লগইন পৃষ্ঠা করছি যা একটি ফর্ম রয়েছে যা জমা দেওয়ার পরে পরবর্তী পৃষ্ঠাটি লোড করার জন্য একটি পোষ্ট অনুরোধ সম্পাদন করবে। এটি ঠিকঠাক কাজ করেছে বলে মনে হচ্ছে তবে অন্যান্য পৃষ্ঠাগুলিতে কনসোলটি নিম্নলিখিত সতর্কতা দেখায়:

সতর্কতা: আনমাউন্ট থাকা উপাদানগুলিতে প্রতিক্রিয়া স্থিতি আপডেট করতে পারে না। এটি কোনও অপশন নয়, তবে এটি আপনার অ্যাপ্লিকেশনটিতে একটি মেমরি ফাঁস নির্দেশ করে। সমাধানের জন্য, ব্যবহারের প্রভাব পরিষ্কার ক্লিনআপ ফাংশনে সমস্ত সাবস্ক্রিপশন এবং অ্যাসিঙ্ক্রোনাস টাস্ক বাতিল করুন।

লগ ইন (জড়তা দ্বারা নির্মিত)

সম্পর্কিত কোড (অপ্রাসঙ্গিক লাইনগুলি এড়ানোর জন্য আমি এটি সরলীকরণ করেছি):

import React, { useEffect, useState } from 'react'
import Layout from "../../Layouts/Auth";

{/** other imports */}

    const login = (props) => {
      const { errors } = usePage();

      const [values, setValues] = useState({email: '', password: '',});
      const [loading, setLoading] = useState(false);

      function handleSubmit(e) {
        e.preventDefault();
        setLoading(true);
        Inertia.post(window.route('login.attempt'), values)
          .then(() => {
              setLoading(false); // Warning : memory leaks during the state update on the unmounted component <--------
           })                                   
      }

      return (
        <Layout title="Access to the system">
          <div>
            <form action={handleSubmit}>
              {/*the login form*/}

              <button type="submit">Access</button>
            </form>
          </div>
        </Layout>
      );
    };

    export default login;

এখন, আমি জানি যে আমাকে একটি ক্লিনআপ ফাংশন করতে হবে কারণ অনুরোধের প্রতিশ্রুতি যা এই সতর্কতাটি উত্পন্ন করছে। আমি জানি যে আমার ব্যবহার করা উচিত useEffectতবে এই ক্ষেত্রে এটি কীভাবে প্রয়োগ করতে হয় তা আমি জানি না। আমি উদাহরণ দেখেছি যখন একটি মান পরিবর্তন হয়, তবে কীভাবে এটি এই ধরণের কলটিতে করবেন?

আগাম ধন্যবাদ.


হালনাগাদ

অনুরোধ হিসাবে, এই উপাদানটির সম্পূর্ণ কোড:

import React, { useState } from 'react'
import Layout from "../../Layouts/Auth";
import { usePage } from '@inertiajs/inertia-react'
import { Inertia } from "@inertiajs/inertia";
import LoadingButton from "../../Shared/LoadingButton";

const login = (props) => {
  const { errors } = usePage();

  const [values, setValues] = useState({email: '', password: '',});

  const [loading, setLoading] = useState(false);

  function handleChange(e) {
    const key = e.target.id;
    const value = e.target.value;

    setValues(values => ({
      ...values,
      [key]: value,
    }))
  }

  function handleSubmit(e) {
    e.preventDefault();
    setLoading(true);
    Inertia.post(window.route('login.attempt'), values)
      .then(() => {
        setLoading(false);
      })
  }

  return (
    <Layout title="Inicia sesión">
      <div className="w-full flex items-center justify-center">
        <div className="w-full max-w-5xl flex justify-center items-start z-10 font-sans text-sm">
          <div className="w-2/3 text-white mt-6 mr-16">
            <div className="h-16 mb-2 flex items-center">                  
              <span className="uppercase font-bold ml-3 text-lg hidden xl:block">
                Optima spark
              </span>
            </div>
            <h1 className="text-5xl leading-tight pb-4">
              Vuelve inteligente tus operaciones
            </h1>
            <p className="text-lg">
              Recoge data de tus instalaciones de forma automatizada; accede a información histórica y en tiempo real
              para que puedas analizar y tomar mejores decisiones para tu negocio.
            </p>

            <button type="submit" className="bg-yellow-600 w-40 hover:bg-blue-dark text-white font-semibold py-2 px-4 rounded mt-8 shadow-md">
              Más información
            </button>
          </div>

        <div className="w-1/3 flex flex-col">
          <div className="bg-white text-gray-700 shadow-md rounded rounded-lg px-8 pt-6 pb-8 mb-4 flex flex-col">
            <div className="w-full rounded-lg h-16 flex items-center justify-center">
              <span className="uppercase font-bold text-lg">Acceder</span>
            </div>

            <form onSubmit={handleSubmit} className={`relative ${loading ? 'invisible' : 'visible'}`}>

              <div className="mb-4">
                <label className="block text-gray-700 text-sm font-semibold mb-2" htmlFor="email">
                  Email
                </label>
                <input
                  id="email"
                  type="text"
                  className=" appearance-none border rounded w-full py-2 px-3 text-gray-700 mb-3 outline-none focus:border-1 focus:border-yellow-500"
                  placeholder="Introduce tu e-mail.."
                  name="email"
                  value={values.email}
                  onChange={handleChange}
                />
                {errors.email && <p className="text-red-500 text-xs italic">{ errors.email[0] }</p>}
              </div>
              <div className="mb-6">
                <label className="block text-gray-700 text-sm font-semibold mb-2" htmlFor="password">
                  Contraseña
                </label>
                <input
                  className=" appearance-none border border-red rounded w-full py-2 px-3 text-gray-700 mb-3 outline-none focus:border-1 focus:border-yellow-500"
                  id="password"
                  name="password"
                  type="password"
                  placeholder="*********"
                  value={values.password}
                  onChange={handleChange}
                />
                {errors.password && <p className="text-red-500 text-xs italic">{ errors.password[0] }</p>}
              </div>
              <div className="flex flex-col items-start justify-between">
                <LoadingButton loading={loading} label='Iniciar sesión' />

                <a className="font-semibold text-sm text-blue hover:text-blue-700 mt-4"
                   href="#">
                  <u>Olvidé mi contraseña</u>
                </a>
              </div>
              <div
                className={`absolute top-0 left-0 right-0 bottom-0 flex items-center justify-center ${!loading ? 'invisible' : 'visible'}`}
              >
                <div className="lds-ellipsis">
                  <div></div>
                  <div></div>
                  <div></div>
                  <div></div>
                </div>
              </div>
            </form>
          </div>
          <div className="w-full flex justify-center">
            <a href="https://optimaee.com">
            </a>
          </div>
        </div>
        </div>
      </div>
    </Layout>
  );
};

export default login;

@ সোহেল আমি এই উপাদানটির সম্পূর্ণ কোড যুক্ত করেছি
কেনি হর্না

আপনি কি সরানোর চেষ্টা করেছেন .then(() => {})?
গেরিক পি

উত্তর:


22

কারণ এটি অ্যাসিঙ্ক প্রতিশ্রুতি কল, সুতরাং অ্যাসিঙ্ক প্রতিক্রিয়াটির পরবর্তী চিকিত্সার জন্য ইতিমধ্যে আনমাউন্টযুক্ত উপাদান (মেমরি ফাঁস এড়ানো ) পরীক্ষা করতে আপনাকে অবশ্যই একটি পরিবর্তনীয় রেফ পরিবর্তনশীল (ইউজারিফ সহ) ব্যবহার করতে হবে :

সতর্কতা: আনমাউন্ট থাকা উপাদানগুলিতে প্রতিক্রিয়া স্থিতি আপডেট করতে পারে না।

দুটি প্রতিক্রিয়া হুক যা আপনাকে এই ক্ষেত্রে ব্যবহার করা উচিত: useRefএবং useEffect

সঙ্গে useRef, উদাহরণস্বরূপ, চপল পরিবর্তনশীল _isMountedসবসময় স্মরণে একই রেফারেন্স দিকে তাক করা হয় (একটি স্থানীয় পরিবর্তনশীল)

যদি পরিবর্তনীয় পরিবর্তনশীল প্রয়োজন হয় তবে ব্যবহাররেফ হু হু হুক। স্থানীয় ভেরিয়েবলগুলির বিপরীতে, প্রতিক্রিয়া প্রতিটি রেন্ডারের সময় একই রেফারেন্স ফিরে আসার বিষয়টি নিশ্চিত করে। আপনি যদি চান তবে এটি ক্লাস কম্পোনেন্টের এই.মাইভারের সাথে একই

উদাহরণ:

const login = (props) => {
  const _isMounted = useRef(true); // Initial value _isMounted = true

  useEffect(() => {
    return () => { // ComponentWillUnmount in Class Component
        _isMounted.current = false;
    }
  }, []);

  function handleSubmit(e) {
    e.preventDefault();
    setLoading(true);
    ajaxCall = Inertia.post(window.route('login.attempt'), values)
        .then(() => {
            if (_isMounted.current) { // Check always mounted component
               // continue treatment of AJAX response... ;
            }
         )
  }
}

একই উপলক্ষে, আমি আপনাকে এখানে ব্যবহৃত প্রতিক্রিয়া হুক সম্পর্কে আরও তথ্য ব্যাখ্যা করতে দিন। এছাড়াও, আমি কার্যকারী উপাদানগুলির প্রতিক্রিয়া হুকগুলি (সংস্করণ প্রতিক্রিয়া> 16.8) সাথে ক্লাস কম্পোনেন্টের লাইফসাইকেলের সাথে তুলনা করব।

ব্যবহারের প্রভাব: বেশিরভাগ পার্শ্ব প্রতিক্রিয়া হুকের অভ্যন্তরে ঘটে। পার্শ্ব প্রতিক্রিয়াগুলির উদাহরণগুলি: ডেটা আনয়ন, সাবস্ক্রিপশন সেট আপ করা এবং প্রতিক্রিয়া উপাদানগুলিতে ম্যানুয়ালি DOM পরিবর্তন করা। ইউজএফেক্টটি ক্লাস কম্পোনেন্টে অনেকগুলি লাইফ সাইকেলকে প্রতিস্থাপিত করে (घटकডিডমাউন্ট, উপাদান-ডিডআপেট, উপাদান-উইলআউনমাউন্ট)

 useEffect(fnc, [dependency1, dependency2, ...]); // dependencies array argument is optional

1) useEffect ডিফল্ট ব্যবহারকে পর উভয় রান প্রথম রেন্ডার (ComponentDidMount মত) এবং প্রতি আপডেটের পরে রেন্ডার (ComponentDidUpdate মত) যদি আপনি নির্ভরতা হবে না। এটা যে মত :useEffect(fnc);

2) ব্যবহারের ক্ষেত্রে নির্ভরতার অ্যারে প্রদানের ফলে তার জীবনচক্রটি পরিবর্তন হবে। এই উদাহরণে: ইউজারএফেক্টটি প্রথম রেন্ডার পরে এবং প্রতিটি বারের গণনা পরিবর্তনের পরে একবার কল করা হবে

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

   useEffect(fnc, [count]);
}

3) যদি আপনি নির্ভরতার জন্য একটি ফাঁকা অ্যারে রাখেন তবে ইউজএফেক্টটি প্রথম রেন্ডারের পরে (কম্পোনেন্টডিডমাউন্টের মতো ) একবারেই চলবে । এটা যে মত :useEffect(fnc, []);

4) সম্পদ তথ্য ফাঁসের প্রতিরোধ করার জন্য, সবকিছু বিন্যস্ত করা আবশ্যক যখন একটি হুক প্রান্ত জীবনচক্র (ComponentWillUnmount মত) । উদাহরণস্বরূপ, নির্ভরতার খালি অ্যারে সহ, ফেরত ফাংশনটি উপাদান আনমাউন্টগুলির পরে ডাকা হবে। এটা যে মত :

useEffect(() => {
   return fnc_cleanUp; // fnc_cleanUp will cancel all subscriptions and asynchronous tasks (ex. : clearInterval) 
}, []);

ইউজারিফ : একটি পরিবর্তনীয় রেফ অবজেক্ট ফেরত দেয় যার। বর্তমান সম্পত্তি পাস হওয়া আর্গুমেন্টের (ইনিশিয়ালভ্যালু) আরম্ভ হয়। প্রত্যাবর্তিত অবজেক্টটি উপাদানটির পুরো জীবনকাল ধরে থাকবে।

উদাহরণ: উপরের প্রশ্নের সাথে আমরা এখানে একটি স্থানীয় ভেরিয়েবল ব্যবহার করতে পারি না কারণ এটি হারিয়ে যাবে এবং প্রতিটি আপডেট রেন্ডারে পুনরায় শুরু হবে।

const login = (props) => {
  let _isMounted= true; // it isn't good because of a local variable, so the variable will be lost and re-initiated on every update render

  useEffect(() => {
    return () => {
        _isMounted = false;  // not good
    }
  }, []);

  // ...
}

সুতরাং, ইউজারফ এবং ইউজএফেক্টের সংমিশ্রণের সাথে আমরা মেমরি ফাঁসকে পুরোপুরি সাফ করতে পারি।


আপনি প্রতিক্রিয়া হুক সম্পর্কে আরও ভাল লিঙ্কগুলি পড়তে পারেন তা হ'ল:

[এএন] https://medium.com/@sdolidze/the-iceberg-of-react-hooks-af0b588f43fb

[এফআর] https://blog.soat.fr/2019/11/react-hooks-par-lexemple/


1
এটি কাজ করে। পরে আজ আমি প্রদত্ত লিঙ্কটি পড়ব আসলে কীভাবে এটি সমস্যার সমাধান করে তা পেতে link আপনি যদি বিবরণটি অন্তর্ভুক্ত করার প্রতিক্রিয়াটি বিশদভাবে বর্ণনা করতে পারেন তবে এটি অন্যের পক্ষে সহায়ক হবে এবং গ্রেস পিরিয়ড পরে আপনাকে অনুদান প্রদান করবে। ধন্যবাদ.
কেনে হর্না

আমার উত্তরটি স্বীকার করার জন্য আপনাকে ধন্যবাদ। আমি আপনার অনুরোধ সম্পর্কে চিন্তা করব এবং আগামীকাল এটি করব।
সানজিমিকা

0

আপনি এর 'cancelActiveVisits' পদ্ধতি ব্যবহার করতে পারে Inertiaসক্রিয় বাতিল করতে visituseEffectপরিষ্করণ হুক।

সুতরাং এই কলটির সাথে সক্রিয়টি visitবাতিল হয়ে যাবে এবং রাষ্ট্র আপডেট হবে না।

useEffect(() => {
    return () => {
        Inertia.cancelActiveVisits(); //To cancel the active visit.
    }
}, []);

যদি Inertiaঅনুরোধটি বাতিল হয়ে যায় তবে এটি একটি খালি প্রতিক্রিয়া ফিরিয়ে দেবে যাতে খালি প্রতিক্রিয়াটি পরিচালনা করতে আপনাকে একটি অতিরিক্ত চেক যোগ করতে হবে। যেকোন সম্ভাব্য ত্রুটিগুলি পরিচালনা করতে অ্যাড ক্যাপ ব্লক যুক্ত করুন।

 function handleSubmit(e) {
    e.preventDefault();
    setLoading(true);
    Inertia.post(window.route('login.attempt'), values)
      .then(data => {
         if(data) {
            setLoading(false);
         }
      })
      .catch( error => {
         console.log(error);
      });
  }

বিকল্প উপায় (workaround)

আপনি useRefউপাদানটির স্থিতি ধরে রাখতে ব্যবহার করতে পারেন এবং এর ভিত্তিতে আপনি আপডেট করতে পারেন state

সমস্যা:

ওয়ার্নিংটি দেখাচ্ছে কারণ handleSubmitউপাদানটি ডোমটি আনমাউন্ট করা সত্ত্বেও উপাদানটির অবস্থা আপডেট করার চেষ্টা করছে।

সমাধান:

স্থিতি রাখা একটি পতাকা সেট component, যদি componentহয় mountedতাহলে flagমান হতে হবে trueএবং যদি componentহয় unmountedপতাকা মান মিথ্যা হবে। সুতরাং এর উপর ভিত্তি করে আমরা আপডেট করতে পারি state। পতাকা স্থিতির জন্য আমরা useRefএকটি রেফারেন্স ধরে রাখতে পারি ।

useRefএমন একটি পরিবর্তনীয় রেফ অবজেক্ট প্রদান করে যার .currentসম্পত্তি পাস হওয়া আর্গুমেন্টের (ইনিশিয়ালভ্যালু) আরম্ভ হয়। প্রত্যাবর্তিত অবজেক্টটি উপাদানটির পুরো জীবনকাল ধরে থাকবে। বিনিময়ে useEffectএকটি ফাংশন যা উপাদানটির স্থিতি নির্ধারণ করে, যদি তা আনমাউন্ট হয়।

এবং তারপরে useEffectক্লিনআপ ফাংশনে আমরা পতাকাটি সেট করতে পারিfalse.

UseEffecr ক্লিনআপ ফাংশন

useEffectহুক একটি পরিষ্করণ ফাংশন ব্যবহার করে দেয়। যে কোনও সময় প্রভাব আর বৈধ থাকে না, উদাহরণস্বরূপ যখন সেই প্রভাবটি ব্যবহার করে কোনও উপাদান আনমাউন্টিং হয় তখন এই ফাংশনটিকে সমস্ত কিছু পরিষ্কার করার জন্য বলা হয়। আমাদের ক্ষেত্রে, আমরা পতাকাটিকে মিথ্যাতে সেট করতে পারি।

উদাহরণ:

let _componentStatus.current =  useRef(true);
useEffect(() => {
    return () => {
        _componentStatus.current = false;
    }
}, []);

এবং হ্যান্ডেলসবমিটে আমরা উপাদানটি মাউন্ট করা আছে কিনা তা পরীক্ষা করতে পারি এবং এর ভিত্তিতে রাষ্ট্র আপডেট করতে পারি।

function handleSubmit(e) {
    e.preventDefault();
    setLoading(true);
    Inertia.post(window.route('login.attempt'), values)
        .then(() => {
            if (_componentStatus.current) {
                setLoading(false);
            } else {
                _componentStatus = null;
            }
        })
}

অন্যথায় _componentStatusকোনও মেমরি ফাঁস এড়াতে শূন্য করতে সেট করুন ।


এটি কার্যকর হয়নি: /
কেনি হর্না

আপনি ajaxCallভিতরে মান সান্ত্বনা দিতে পারেন useEffect। এবং মানটি দেখুন
সোহেল

দেরি করার জন্য দুঃখিত. এটি ফিরে আসে undefined। আমি এটিকে যুক্ত করেছিreturn () => {
কেনি হর্না

আমি কোডটি পরিবর্তন করেছি, দয়া করে নতুন কোডটি চেষ্টা করুন।
সোহেল

আমি এটি বলব না যে এটি এই সমস্যাটি সমাধানের একটি সঠিক বা সঠিক উপায়, তবে এটি সতর্কতা সরিয়ে দেবে।
সোহেল
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.