ব্যবহারের প্রভাব অসীম লুপ


105

আমি ১ h..7-আলফা প্রতিক্রিয়াতে নতুন হুক সিস্টেমে ঘুরে বেড়াচ্ছি এবং যখন আমি যে রাজ্যটি পরিচালনা করছি তখন কোনও অবজেক্ট বা অ্যারে হ'ল ব্যবহারের প্রভাবতে অসীম লুপে আটকে যাব।

প্রথমত, আমি ইউজস্টেট ব্যবহার করি এবং এটির মতো একটি খালি বস্তু দিয়ে এটি শুরু করি:

const [obj, setObj] = useState({});

তারপরে, UseEffect এ আবার সেট করে খালি অবজেক্টে সেট করতে আমি setObj ব্যবহার করি। দ্বিতীয় যুক্তি হিসাবে আমি [ অবজেক্ট ] পাশ করছি, আশা করছি যে যদি অবজেক্টের সামগ্রী পরিবর্তন না হয় তবে এটি আপডেট হবে না। তবে এটি আপডেট হতে থাকে। আমার অনুমান কারণ বিষয়বস্তু কোনও কারণই নয়, এগুলি সর্বদা ভিন্ন ভিন্ন বস্তু যা এটি পরিবর্তন করে কি তা ভেবে প্রতিক্রিয়া তৈরি করে?

useEffect(() => {
  setIngredients({});
}, [ingredients]);

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

এই নতুন হুক ব্যবহার করে বিষয়বস্তু পরিবর্তন হয়েছে কিনা তা পরীক্ষা করার সময় আমি কীভাবে অবজেক্টস এবং অ্যারে পরিচালনা করব?


টোবিয়াস, কোন ব্যবহারের ক্ষেত্রে উপাদানগুলির মান পরিবর্তন করা দরকার, একবার এর মান পরিবর্তন হয়ে গেলে?
বেন কার্প

@ তোবিয়াস, আপনার আমার উত্তরটি পড়া উচিত। আমি নিশ্চিত আপনি এটি সঠিক উত্তর হিসাবে গ্রহণ করবেন।
হাফওয়েবদেভ

উত্তর:


122

ইমফ্যাক্টের দ্বিতীয় আর্গুমেন্ট হিসাবে একটি খালি অ্যারে পাস করা এটি কেবল মাউন্ট এবং আনমাউন্টে চালিত করে, ফলে কোনও অসীম লুপ বন্ধ হয়ে যায়।

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

এটি https://www.robinwieruch.de/react-hooks/ এ প্রতিক্রিয়া হুক সম্পর্কিত ব্লগ পোস্টে আমার কাছে স্পষ্ট করা হয়েছিল


4
এটি আসলে একটি খালি অ্যারে নয় এমন কোনও শূন্য বস্তু যা আপনার পাস করা উচিত
জিফকো

16
এটি সমস্যার সমাধান করে না, আপনি হুক দ্বারা ব্যবহৃত নির্ভরতাগুলি পাস করতে হবে
হেলাদো

4
মনে রাখবেন যে আনমাউন্টে প্রভাবটি একটি পরিষ্কারআপ ফাংশন চালাবে যদি আপনি একটি নির্দিষ্ট করে থাকেন। আসল প্রভাব আনমাউন্টে চলবে না। reactjs.org/docs/hooks-effect.html#example- using
টনি

4
ড্যান আব্রামভ যেমন বলেছিলেন সেটগ্রিগ্রায়েটগুলি নির্ভর করে তখন খালি অ্যারে ব্যবহার করা একটি প্রতিরোধ ব্যবস্থা। ডিফল্ট মাউন্ট () পদ্ধতির মতো ব্যবহারের চিকিত্সা করবেন না
p7adams

4
যেহেতু মানুষ উপরে কিভাবে সঠিকভাবে এই সমস্যা সমাধানের জন্য একটি লিঙ্ক বা সম্পদ প্রদান করা হয়নি, আমি এই চেক আউট করতে আসন্ন duckduckgoers সুপারিশ, যেহেতু এটি আমার অসীম লুপ সমস্যা সংশোধন: stackoverflow.com/questions/56657907/...
সি পাঁজর

72

একই সমস্যা ছিল। আমি জানি না কেন তারা ডক্সে এটি উল্লেখ করে না। টোবিয়াস হগেন উত্তরে কেবল কিছুটা যুক্ত করতে চাই।

প্রতিটি উপাদান / পিতামাতার রেন্ডারারে চালানোর জন্য আপনাকে ব্যবহার করতে হবে:

  useEffect(() => {

    // don't know where it can be used :/
  })

উপাদান মাউন্টের পরে কেবলমাত্র একবার চালানোর জন্য (একবারে রেন্ডার করা হবে) আপনাকে ব্যবহার করতে হবে:

  useEffect(() => {

    // do anything only one time if you pass empty array []
    // keep in mind, that component will be rendered one time (with default values) before we get here
  }, [] )

উপাদান মাউন্ট এবং ডেটা / ডেটা 2 পরিবর্তনতে একসময় যে কোনও কিছু চালাতে :

  const [data, setData] = useState(false)
  const [data2, setData2] = useState('default value for first render')
  useEffect(() => {

// if you pass some variable, than component will rerender after component mount one time and second time if this(in my case data or data2) is changed
// if your data is object and you want to trigger this when property of object changed, clone object like this let clone = JSON.parse(JSON.stringify(data)), change it clone.prop = 2 and setData(clone).
// if you do like this 'data.prop=2' without cloning useEffect will not be triggered, because link to data object in momory doesn't changed, even if object changed (as i understand this)
  }, [data, data2] )

আমি কীভাবে এটি বেশিরভাগ সময় ব্যবহার করি:

export default function Book({id}) { 
  const [book, bookSet] = useState(false) 

  useEffect(() => {
    loadBookFromServer()
  }, [id]) // every time id changed, new book will be loaded

  // Remeber that it's not always safe to omit functions from the list of dependencies. Explained in comments.
  async function loadBookFromServer() {
    let response = await fetch('api/book/' + id)
    response  = await response.json() 
    bookSet(response)
  }

  if (!book) return false //first render, when useEffect did't triggered yet we will return false

  return <div>{JSON.stringify(book)}</div>  
}


@ এন্ডাভিড আপনি যে
প্রপটিটি

4
অবশ্যই, আপনি যদি উপাদান উপাদান থেকে কোনও মান ব্যবহার না করেন তবে এটি বাদ দেওয়া নিরাপদ। তবে বিশুদ্ধরূপে ডিজাইনিং / আর্কিটেকচারিং পয়েন্ট থেকে, এটি একটি ভাল অনুশীলন নয়, কারণ আপনার যদি প্রপস ব্যবহার করার প্রয়োজন হয় তবে আপনাকে আপনার পুরো ফাংশনটি প্রভাবের ভিতরে নিয়ে যেতে হবে এবং আপনি একটি ব্যবহারের কার্যকর পদ্ধতিটি শেষ করতে পারেন যা ব্যবহার করবে কোড লাইন ভয়ানক পরিমাণ।
egdavid

16

আমিও একবার একই সমস্যায় পড়েছিলাম এবং দ্বিতীয় যুক্তিতে আমি আদিম মানগুলি নিশ্চিত করে তা স্থির করেছিলাম []

আপনি যদি কোনও বস্তুটি পাস করেন, প্রতিক্রিয়া কেবলমাত্র অবজেক্টের রেফারেন্স সংরক্ষণ করে এবং রেফারেন্স পরিবর্তিত হলে প্রভাবটি চালিত করবে, যা সাধারণত প্রতিটি সময় সময় হয় (আমি এখন কিভাবে তা করি না)।

সমাধানটি হল অবজেক্টের মানগুলি পাস করা। আপনি চেষ্টা করতে পারেন,

const obj = { keyA: 'a', keyB: 'b' }

useEffect(() => {
  // do something
}, [Object.values(obj)]);

বা

const obj = { keyA: 'a', keyB: 'b' }

useEffect(() => {
  // do something
}, [obj.keyA, obj.keyB]);

4
আরেকটি পদ্ধতির ব্যবহার মেমো দিয়ে এই জাতীয় মান তৈরি করা হয়, যেভাবে রেফারেন্সটি রাখা হয় এবং নির্ভরতার মানগুলি একই হিসাবে মূল্যায়ন করা হয়
হেলাদো

@ হেলাদো আপনি মানগুলির জন্য ব্যবহারেমো () ব্যবহার করতে পারেন বা ফাংশনগুলির জন্য কলব্যাক () ব্যবহার করতে পারেন
জুয়ানমা মেনেন্ডেজ

11

ডকুমেন্টেশনে যেমন বলা হয়েছে ( https://reactjs.org/docs/hooks-effect.html ), আপনি প্রতিটি রেন্ডারের পরে কিছু কোড কার্যকর করতে চাইলেuseEffect হুক ব্যবহার করা হয় । ডক্স থেকে:

ইউজএফেক্ট প্রতিটি রেন্ডার পরে চলে? হ্যাঁ!

আপনি যদি এটি কাস্টমাইজ করতে চান তবে আপনি একই পৃষ্ঠায় পরবর্তী নির্দেশাবলী অনুসরণ করতে পারেন ( https://reactjs.org/docs/hooks-effect.html#tip-optimizing-performance-by-skipping-effects )। মূলত, useEffectপদ্ধতিটি একটি দ্বিতীয় যুক্তি গ্রহণ করে , যে প্রতিক্রিয়াটি পরীক্ষাটি পরীক্ষা করে দেখাবে যে প্রভাবটি আবার ট্রিগার করতে হবে কিনা তা নির্ধারণ করতে।

useEffect(() => {
  document.title = `You clicked ${count} times`;
}, [count]); // Only re-run the effect if count changes

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


11

যদি আপনি একটি কাস্টম হুক তৈরি করছেন তবে আপনি কখনও কখনও নীচের হিসাবে ডিফল্ট সহ অসীম লুপ তৈরি করতে পারেন

function useMyBadHook(values = {}) {
    useEffect(()=> { 
           /* This runs every render, if values is undefined */
        },
        [values] 
    )
}

ফিক্সটি হ'ল প্রতিটি ফাংশন কলে নতুন একটি তৈরি করার পরিবর্তে একই অবজেক্টটি ব্যবহার করা:

const defaultValues = {};
function useMyBadHook(values = defaultValues) {
    useEffect(()=> { 
           /* This runs on first call and when values change */
        },
        [values] 
    )
}

আপনি যদি নিজের উপাদান উপাদানটিতে এটির মুখোমুখি হন তবে আপনি ES6 ডিফল্ট মানগুলির পরিবর্তে ডিফল্টপ্রোপগুলি ব্যবহার করলে লুপটি ঠিক হয়ে যেতে পারে

function MyComponent({values}) {
  useEffect(()=> { 
       /* do stuff*/
    },[values] 
  )
  return null; /* stuff */
}

MyComponent.defaultProps = {
  values = {}
}

ধন্যবাদ! এটি আমার কাছে অ-স্পষ্টতই ছিল এবং ঠিক আমি যে সমস্যার মধ্যে চলেছিলাম।
আটকে গেল

4
তুমি আমার দিন বাঁচিয়েছ! ধন্যবাদ ভাই.
হান ভ্যান ফ্যাম

6

আমি নিশ্চিত না যে এটি আপনার পক্ষে কাজ করে কিনা তবে আপনি। দৈর্ঘ্য যুক্ত করার চেষ্টা করতে পারেন:

useEffect(() => {
        // fetch from server and set as obj
}, [obj.length]);

আমার ক্ষেত্রে (আমি একটি অ্যারে আনছিলাম!) এটি মাউন্টে ডেটা এনেছে, তারপরে আবার কেবল পরিবর্তন হবে এবং এটি লুপে যায় নি।


4
অ্যারেতে যদি কোনও আইটেম প্রতিস্থাপন করা হয় তবে কী হবে? সেক্ষেত্রে অ্যারের দৈর্ঘ্য একই হবে এবং প্রভাবটি চলবে না!
আমির খান

5

আপনি যদি ব্যবহারের শেষে খালি অ্যারে অন্তর্ভুক্ত করেন :

useEffect(()=>{
        setText(text);
},[])

এটি একবার চালানো হবে।

আপনি যদি অ্যারেতেও প্যারামিটার অন্তর্ভুক্ত করেন:

useEffect(()=>{
            setText(text);
},[text])

এটি যখনই পাঠ্য পরামিতি পরিবর্তিত হবে run


যদি আমরা একটি হুকের শেষে একটি খালি অ্যারে রাখি তবে এটি কেন একবারে চলবে?
ক্যারেন

ইউজএফেক্টের শেষে একটি ফাঁকা অ্যারে হ'ল ডেভেলপাররা এমন পরিস্থিতিতে অসীম লুপগুলি থামানোর উদ্দেশ্যে উদ্দেশ্যমূলক বাস্তবায়ন যেখানে আপনি সম্ভবত উদাহরণস্বরূপ ব্যবহারের প্রভাবের অভ্যন্তরে সেটস্টেটের প্রয়োজন হতে পারেন। এটি অন্যথায় ব্যবহারের প্রভাব -> স্টেট আপডেট -> ইউজেক্ট -> অসীম লুপের দিকে নিয়ে যায়।
টু 40

4

আপনার অসীম লুপটি বৃত্তাকার কারণে

useEffect(() => {
  setIngredients({});
}, [ingredients]);

setIngredients({});ingredients(প্রতিটি সময় একটি নতুন রেফারেন্স ফিরে আসবে) এর মান পরিবর্তন করবে, যা চলবে setIngredients({})। এটি সমাধানের জন্য আপনি উভয় পদ্ধতির ব্যবহার করতে পারেন:

  1. ব্যবহারের জন্য একটি ভিন্ন দ্বিতীয় তর্কটি পাস করুন
const timeToChangeIngrediants = .....
useEffect(() => {
  setIngredients({});
}, [timeToChangeIngrediants ]);

setIngrediantstimeToChangeIngrediantsপরিবর্তন হবে যখন চালানো হবে ।

  1. আমি নিশ্চিত নই যে কোন ব্যবহারের ক্ষেত্রে উপাদানগুলি পরিবর্তিত হওয়ার পরে তা ন্যায্যতা প্রমাণিত হয়। তবে যদি এটি হয় তবে Object.values(ingrediants)আপনি ব্যবহারের দ্বিতীয় তর্ক হিসাবে পাস করুন ।
useEffect(() => {
  setIngredients({});
}, Object.values(ingrediants));

2

আপনি যদি এই অপটিমাইজেশন ব্যবহার করেন তবে নিশ্চিত হয়ে নিন যে অ্যারেতে উপাদান ব্যবস্থার সমস্ত মান (যেমন প্রপস এবং রাজ্য) অন্তর্ভুক্ত রয়েছে যা সময়ের সাথে সাথে পরিবর্তিত হয় এবং যা প্রভাব দ্বারা ব্যবহৃত হয়।

আমি বিশ্বাস করি যে তারা বাসি ডেটা ব্যবহার করতে পারে এবং এই সম্পর্কে সচেতন হওয়ার সম্ভাবনাটি প্রকাশ করার চেষ্টা করছেন। arrayদ্বিতীয় আর্গুমেন্টের জন্য আমরা যে ধরণের মান প্রেরণ করি তা ততক্ষণ গুরুত্বপূর্ণ নয় যতক্ষণ না আমরা জানি যে এই মানগুলির কোনও পরিবর্তন হলে এটি কার্যকর করে দেবে। যদি আমরা ingredientsপ্রভাবের মধ্যে গণনার অংশ হিসাবে ব্যবহার করি তবে আমাদের এটিতে অন্তর্ভুক্ত করা উচিত array

const [ingredients, setIngredients] = useState({});

// This will be an infinite loop, because by shallow comparison ingredients !== {} 
useEffect(() => {
  setIngredients({});
}, [ingredients]);

// If we need to update ingredients then we need to manually confirm 
// that it is actually different by deep comparison.

useEffect(() => {
  if (is(<similar_object>, ingredients) {
    return;
  }
  setIngredients(<similar_object>);
}, [ingredients]);


1

সবচেয়ে ভালো উপায় ব্যবহার করে বর্তমান মান আগের মান তুলনা হয় usePrevious () এবং _.isEqual () থেকে Lodash । আমদানি ইস্কুল এবং ইউজারিফ । আপনার আগের মানটি ব্যবহারের প্রভাব () এর অভ্যন্তরে বর্তমান মানের সাথে তুলনা করুন । তারা যদি একই হয় তবে আর কিছু আপডেট করবেন না। ইউজপ্রিরিউস (মান) হ'ল একটি কাস্টম হুক যা ব্যবহারের সাথে রেফ তৈরি করে ()

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

import React, { useState, useEffect, useRef } from 'react'
import 'firebase/database'
import { Redirect } from 'react-router-dom'
import { isEqual } from 'lodash'
import {
  useUserStatistics
} from '../../hooks/firebase-hooks'

export function TMDPage({ match, history, location }) {
  const usePrevious = value => {
    const ref = useRef()
    useEffect(() => {
      ref.current = value
    })
    return ref.current
  }
  const userId = match.params ? match.params.id : ''
  const teamId = location.state ? location.state.teamId : ''
  const [userStatistics] = useUserStatistics(userId, teamId)
  const previousUserStatistics = usePrevious(userStatistics)

  useEffect(() => {
      if (
        !isEqual(userStatistics, previousUserStatistics)
      ) {
        
        doSomething()
      }
     
  })


4
আমার ধারণা, লোকেরা এটি হ্রাস পেয়েছে কারণ আপনি তৃতীয় পক্ষের লাইব্রেরিটি ব্যবহার করার পরামর্শ দিয়েছেন। তবে অন্তর্নিহিত ধারণাটি ভাল।
jperl

1

যদি আপনাকে অবজেক্টটির তুলনা করতে হবে এবং এটি এখানে আপডেট হয় তখন deepCompareতুলনার জন্য একটি হুক is গৃহীত উত্তর অবশ্যই তা বিবেচনা করে না। একটি হচ্ছে [], আপনি যদি শুধুমাত্র একবার যখন মাউন্ট চালানোর প্রভাব প্রয়োজন অ্যারে উপযুক্ত।

এছাড়াও, অন্যান্য ভোট দেওয়া উত্তরগুলি আদিম প্রকারের জন্য কেবল একটি চেককে সম্বোধন করে obj.valueবা প্রথমে যেখানে স্তন্যপান হয় না সেখানে পৌঁছানোর অনুরূপ address গভীর ঘৃণ্য বস্তুগুলির জন্য এটি সেরা ক্ষেত্রে নাও হতে পারে।

সুতরাং এখানে একটি যা সব ক্ষেত্রেই কাজ করবে।

import { DependencyList } from "react";

const useDeepCompare = (
    value: DependencyList | undefined
): DependencyList | undefined => {
    const ref = useRef<DependencyList | undefined>();
    if (!isEqual(ref.current, value)) {
        ref.current = value;
    }
    return ref.current;
};

আপনি useEffectহুক একই ব্যবহার করতে পারেন

React.useEffect(() => {
        setState(state);
    }, useDeepCompare([state]));

0

আপনি নির্ভরতা অ্যারেতে অবজেক্টটিও বিন্যাস করতে পারেন, অর্থ রাষ্ট্রের কেবল তখন আপডেট হবে যখন বস্তুর কিছু অংশ আপডেট হবে updated

এই উদাহরণের স্বার্থে, আসুন বলি যে উপাদানগুলিতে গাজর রয়েছে, আমরা এটিকে নির্ভরতার কাছে পৌঁছে দিতে পারি, এবং কেবল যদি গাজর পরিবর্তন হয় তবে রাষ্ট্র আপডেট হবে।

এরপরে আপনি এটিকে আরও গ্রহণ করতে পারেন এবং কেবল নির্দিষ্ট পয়েন্টগুলিতে গাজরের সংখ্যা আপডেট করতে পারেন, এভাবে রাষ্ট্র কখন আপডেট হবে এবং একটি অসীম লুপ এড়িয়ে চলবে তা নিয়ন্ত্রণ করে।

useEffect(() => {
  setIngredients({});
}, [ingredients.carrots]);

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


0

আমার কেস অসীম লুপের মুখোমুখি হওয়ার বিষয়ে বিশেষ ছিল, স্যানারিও এইরকম ছিল:

আমার একটি অবজেক্ট ছিল, প্রজ থেকে আসা অবজ্যাক বলতে দিন এবং আমি প্রপসগুলিতে এটি ধ্বংস করেছিলাম:

const { something: { somePropery } } = ObjX

এবং আমি someProperyআমার useEffectপছন্দ মতো নির্ভরতা হিসাবে ব্যবহার করেছি :


useEffect(() => {
  // ...
}, [somePropery])

এবং এটি আমার জন্য একটি অসীম লুপ ঘটায়, আমি পুরোপুরি somethingনির্ভরতা হিসাবে পেরিয়ে এটি পরিচালনা করার চেষ্টা করেছি এবং এটি সঠিকভাবে কাজ করেছে।

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