ব্যবহারের ক্ষেত্রে অ্যাসিঙ্ক ফাংশনটির জন্য হুক সতর্কতা প্রতিক্রিয়া করুন


142

আমি useEffectনীচের মতো উদাহরণটি চেষ্টা করছিলাম :

useEffect(async () => {
    try {
        const response = await fetch(`https://www.reddit.com/r/${subreddit}.json`);
        const json = await response.json();
        setPosts(json.data.children.map(it => it.data));
    } catch (e) {
        console.error(e);
    }
}, []);

এবং আমি আমার কনসোলটিতে এই সতর্কতা পেয়েছি। তবে আমার মনে হয় অ্যাসিঙ্ক কলগুলির জন্য ক্লিনআপটি alচ্ছিক। আমি কেন এই সতর্কতা পেয়েছি তা নিশ্চিত নই। উদাহরণস্বরূপ স্যান্ডবক্সের লিঙ্ক করা। https://codesandbox.io/s/24rj871r0p এখানে চিত্র বর্ণনা লিখুন

উত্তর:


199

আমি ড্যান আব্রামভ (প্রতিক্রিয়া মূল রক্ষণাবেক্ষণকারীদের মধ্যে একটি) উত্তরটি এখানে দেখার পরামর্শ দিই :

আমি মনে করি আপনি এটি করা প্রয়োজনের চেয়ে জটিল করে তুলছেন।

function Example() {
  const [data, dataSet] = useState<any>(null)

  useEffect(() => {
    async function fetchMyAPI() {
      let response = await fetch('api/data')
      response = await response.json()
      dataSet(response)
    }

    fetchMyAPI()
  }, [])

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

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

const response = MyAPIResource.read();

এবং কোন প্রভাব। তবে এর মধ্যে আপনি অ্যাসিঙ্ক স্টাফটিকে একটি পৃথক ফাংশনে স্থানান্তর করতে এবং কল করতে পারেন।

আপনি এখানে পরীক্ষামূলক সাসপেন্স সম্পর্কে আরও পড়তে পারেন ।


আপনি যদি এসলিন্ট দিয়ে বাইরে ফাংশন ব্যবহার করতে চান।

 function OutsideUsageExample() {
  const [data, dataSet] = useState<any>(null)

  const fetchMyAPI = useCallback(async () => {
    let response = await fetch('api/data')
    response = await response.json()
    dataSet(response)
  }, [])

  useEffect(() => {
    fetchMyAPI()
  }, [fetchMyAPI])

  return (
    <div>
      <div>data: {JSON.stringify(data)}</div>
      <div>
        <button onClick={fetchMyAPI}>manual fetch</button>
      </div>
    </div>
  )
}

UseCallback useCallbackস্যান্ডবক্স

import React, { useState, useEffect, useCallback } from "react";

export default function App() {
  const [counter, setCounter] = useState(1);

  // if counter is changed, than fn will be updated with new counter value
  const fn = useCallback(() => {
    setCounter(counter + 1);
  }, [counter]);

  // if counter is changed, than fn will not be updated and counter will be always 1 inside fn
  /*const fnBad = useCallback(() => {
      setCounter(counter + 1);
    }, []);*/

  // if fn or counter is changed, than useEffect will rerun
  useEffect(() => {
    if (!(counter % 2)) return; // this will stop the loop if counter is not even

    fn();
  }, [fn, counter]);

  // this will be infinite loop because fn is always changing with new counter value
  /*useEffect(() => {
    fn();
  }, [fn]);*/

  return (
    <div>
      <div>Counter is {counter}</div>
      <button onClick={fn}>add +1 count</button>
    </div>
  );
}

আপনি উপাদানটি এমনভাবে আনমাউন্ট করা হয়েছে কিনা তা পরীক্ষা করে রেসের শর্তগুলির সমস্যাগুলি সমাধান করতে পারেন: useEffect(() => { let unmounted = false promise.then(res => { if (!unmounted) { setState(...) } }) return () => { unmounted = true } }, [])
রিচার্ড

4
আপনি ব্যবহার-অ্যাসিঙ্ক-প্রভাব নামে একটি প্যাকেজও ব্যবহার করতে পারেন । এই প্যাকেজটি আপনাকে async অপেক্ষার সিনট্যাক্স ব্যবহার করতে সক্ষম করে।
কিটিক্যাটেক 1'19

স্ব-আহ্বানকারী ফাংশনটি ব্যবহার করে এ্যাসিঙ্কটি ব্যবহারের প্রভাব ফাংশন সংজ্ঞাতে বা এমন কোনও ফাংশনের একটি কাস্টম বাস্তবায়ন যা ব্যবহারের চারপাশে একটি মোড়ক হিসাবে অ্যাসিঙ্ক কলকে ট্রিগার করে তা আপাতত সেরা বাজি। আপনি প্রস্তাবিত ব্যবহার-অ্যাসিঙ্ক-ইফেক্টের মতো একটি নতুন প্যাকেজ অন্তর্ভুক্ত করতে পারবেন বলে আমি মনে করি এটি সমাধান করা সহজ সমস্যা।
থুলানী চিভান্দিকওয়া

4
আরে এটা ঠিক আছে এবং আমি বেশিরভাগ সময়ই করি। তবে eslintআমাকে তার fetchMyAPI()নির্ভরতা হিসাবে তৈরি করতে বলেuseEffect
প্রকাশ রেড্ডি পটলপাদু

52

আপনি যখন একটি অ্যাসিঙ্ক ফাংশন ব্যবহার করেন

async () => {
    try {
        const response = await fetch(`https://www.reddit.com/r/${subreddit}.json`);
        const json = await response.json();
        setPosts(json.data.children.map(it => it.data));
    } catch (e) {
        console.error(e);
    }
}

এটি একটি প্রতিশ্রুতি ফিরিয়ে দেয় এবং useEffectকলব্যাক ফাংশনটি প্রতিশ্রুতি ফেরানোর প্রত্যাশা করে না, বরং এটি প্রত্যাশা করে যে কিছুই প্রত্যাবর্তিত হয়নি বা কোনও ফাংশন প্রত্যাবর্তিত হয়েছে।

সতর্কবার্তাটির কার্যকারিতা হিসাবে আপনি একটি স্ব-আমন্ত্রণকারী অ্যাসিঙ্ক ফাংশন ব্যবহার করতে পারেন।

useEffect(() => {
    (async function() {
        try {
            const response = await fetch(
                `https://www.reddit.com/r/${subreddit}.json`
            );
            const json = await response.json();
            setPosts(json.data.children.map(it => it.data));
        } catch (e) {
            console.error(e);
        }
    })();
}, []);

বা এটিকে আরও পরিষ্কার করার জন্য আপনি কোনও ফাংশন সংজ্ঞায়িত করতে পারেন এবং তারপরে কল করতে পারেন

useEffect(() => {
    async function fetchData() {
        try {
            const response = await fetch(
                `https://www.reddit.com/r/${subreddit}.json`
            );
            const json = await response.json();
            setPosts(json.data.children.map(it => it.data));
        } catch (e) {
            console.error(e);
        }
    };
    fetchData();
}, []);

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

ওয়ার্কিং কোডস্যান্ডবক্স


এটিকে আরও সহজ করার জন্য একটি প্যাকেজ তৈরি করা হয়েছে। আপনি এটি এখানে খুঁজে পেতে পারেন ।
কিটিটিজ

4
তবে এসিলিন্ট এতে সহ্য করবে না
মুহাইমিন সিএস

4
ক্লিনআপ / ডডমাউন্ট কলব্যাক চালানোর কোনও উপায় নেই
ডেভিড রিয়ার্ট

4
@ শুভখত্রি আপনি যখন ব্যবহার করেন তখন useEffectকোনও অনুষ্ঠান ফিরিয়ে দিতে পারতেন ইভেন্টগুলিতে সাবস্ক্রাইব করার মতো ক্লিন আপ। আপনি যখন অ্যাসিঙ্ক ফাংশনটি ব্যবহার করেন আপনি কোনও কিছুই ফিরিয়ে দিতে পারবেন না কারণ useEffect
ফলাফলটির

4
আপনি কি বলছেন যে আমি একটি অ্যাসিঙ্ক একটিতে একটি ক্লিন আপ ফাংশন রাখতে পারি? আমি চেষ্টা করেছি কিন্তু আমার ক্লিন আপ ফাংশনটি কখনই ডাকা হয় না। আপনি একটি সামান্য উদাহরণ করতে পারেন?
ডেভিড রিয়ার্ট

33

প্রতিক্রিয়া কোনও ভাল উপায় না দেওয়া পর্যন্ত আপনি একটি সহায়ক তৈরি করতে পারেন useEffectAsync.js,:

import { useEffect } from 'react';


export default function useEffectAsync(effect, inputs) {
    useEffect(() => {
        effect();
    }, inputs);
}

এখন আপনি একটি অ্যাসিঙ্ক ফাংশনটি পাস করতে পারেন:

useEffectAsync(async () => {
    const items = await fetchSomeItems();
    console.log(items);
}, []);

9
প্রতিক্রিয়া স্বয়ংক্রিয়ভাবে ব্যবহারের প্রভাবগুলিতে অ্যাসিঙ্ক ফাংশনগুলিকে মঞ্জুরি দেয় না কারণ হ'ল বিশাল আকারের ক্ষেত্রে, কিছু সাফাই প্রয়োজন। আপনি যে ফাংশনটি useAsyncEffectলিখেছেন এটি সহজেই কাউকে ভাবতে ভ্রান্ত করতে পারে যদি তারা যদি তাদের অ্যাসিঙ্ক প্রভাব থেকে কোনও ক্লিনআপ ফাংশনটি ফেরত দেয় তবে এটি উপযুক্ত সময়ে চালানো হবে। এটি মেমরি ফাঁস বা আরও খারাপ ত্রুটির দিকে পরিচালিত করতে পারে, তাই আমরা লোকেদের রিএ্যাক্টের জীবনচক্রের সাথে ইন্টারঅ্যাক্ট করে অ্যাসিঙ্ক ফাংশনগুলির "সিম" তৈরি করতে তাদের কোডটি রিফ্যাক্ট করতে উত্সাহিত করার সিদ্ধান্ত নিয়েছিলাম এবং ফলাফলের হিসাবে কোডটির আচরণ আশাবাদী আরও ইচ্ছাকৃত এবং সঠিক।
সোফি আল্পার্ট

8

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

const [data, setData] = useState(null);

/* This would be called on initial page load */
useEffect(()=>{
    fetch(`https://www.reddit.com/r/${subreddit}.json`)
    .then(data => {
        setData(data);
    })
    .catch(err => {
        /* perform error handling if desired */
    });
}, [])

/* This would be called when store/state data is updated */
useEffect(()=>{
    if (data) {
        setPosts(data.children.map(it => {
            /* do what you want */
        }));
    }
}, [data]);

রেফারেন্স => https://reactjs.org/docs/hooks-effect.html#tip-optimizing-performance-by-skipping-effects


4

অন্যান্য পাঠকদের জন্য ত্রুটিটি এই সত্য থেকে আসতে পারে যে অ্যাসিঙ্ক ফাংশনটি মোড়ানো কোনও বন্ধনী নেই:

Async ফাংশন initData বিবেচনা করে

  async function initData() {
  }

এই কোডটি আপনার ত্রুটির দিকে পরিচালিত করবে:

  useEffect(() => initData(), []);

কিন্তু এই, না:

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

(আরডিডিটার চারপাশে বন্ধনী লক্ষ্য করুন ()


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

4
লোকেরা যদি ভাবছে যে কেন এটি সত্য ... কোঁকড়ানো ধনুর্বন্ধনীগুলি ছাড়া, তীর ফাংশন দ্বারা ইনডিটাটা () এর প্রত্যাবর্তন মান সুস্পষ্টভাবে ফিরে আসে। কোঁকড়া ধনুর্বন্ধনী সঙ্গে, কিছুই স্পষ্টভাবে ফিরে আসে না এবং এইভাবে ত্রুটি ঘটবে না।
মার্নিক্স.হোহ

4

অকার্যকর অপারেটর এখানে ব্যবহার করা যেতে পারে।
পরিবর্তে:

React.useEffect(() => {
    async function fetchData() {
    }
    fetchData();
}, []);

বা

React.useEffect(() => {
    (async function fetchData() {
    })()
}, []);

আপনি লিখতে পারেন:

React.useEffect(() => {
    void async function fetchData() {
    }();
}, []);

এটি একটি সামান্য পরিষ্কার এবং সুন্দর।


অ্যাসিঙ্ক প্রভাবগুলি মেমরি ফাঁসের কারণ হতে পারে তাই উপাদান আনমাউন্টে সাফ করা গুরুত্বপূর্ণ। আনার ক্ষেত্রে এটি দেখতে এরকম হতে পারে:

function App() {
  const [data, setData] = React.useState([])

  React.useEffect(() => {
    const abortController = new AbortController()
    ;(async function fetchData() {
      try {
        const url = "https://jsonplaceholder.typicode.com/todos/1"
        const response = await fetch(url, {
          signal: abortController.signal,
        })
        setData(await response.json())
      } catch (error) {
        console.log("error", error)
      }
    })()
    return abortController.abort // cancel pending fetch request on component unmount
  }, [])

  return <pre>{JSON.stringify(data, null, 2)}</pre>
}


আপনি আপনার জেএস জানেন, স্যার। অ্যাবোর্টকন্ট্রোলার হ'ল নতুন ফিঙ্গাল জিনিস যা বাতিল প্রতিশ্রুতি প্রস্তাব ব্যর্থ হওয়ার পরে পাওয়া যায়
ডেভিন জি রোড

বিটিডাব্লু সেখানে এই "ইউজ-অ্যাওরটেবল-ফেঞ্চ" প্যাকেজটি রয়েছে তবে এটি কীভাবে লেখা হয়েছিল তা আমি পছন্দ করি না। আপনার এখানে কাস্টম হুক হিসাবে এই কোডটির একটি সাধারণ সংস্করণ পাওয়া ভাল হবে। এছাড়াও, "অপেক্ষা-এখানে" একটি দুর্দান্ত প্যাকেজ যা একটি চেষ্টা / ক্যাচ ব্লকের প্রয়োজনীয়তা হ্রাস করতে পারে।
ডেভিন জি রোড

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