অ্যাসিঙ্ক উপাদান ডিডমাউন্ট () ব্যবহার করা ভাল?


139

componentDidMount()প্রতিক্রিয়া নেটিভ এ্যাসিঙ্ক ফাংশন হিসাবে ব্যবহার করা ভাল অভ্যাস হিসাবে ব্যবহার করা উচিত বা আমার এড়ানো উচিত?

AsyncStorageউপাদানটি মাউন্ট করার সময় থেকে আমার কিছু তথ্য নেওয়া দরকার , তবে এটি সম্ভব করার জন্য আমি জানার একমাত্র componentDidMount()উপায়টি হ'ল ফাংশনটিকে অ্যাসিঙ্ক করা।

async componentDidMount() {
    let auth = await this.getAuth();
    if (auth) 
        this.checkAuth(auth);
}

এটি নিয়ে কোনও সমস্যা আছে এবং এই সমস্যার কোনও সমাধান আছে কি?


1
"ভালো অনুশীলন" একটি মতামতের বিষয়। এটা কি কাজ করে? হ্যাঁ.
ক্রাইলগ

2
এখানে একটি ভাল নিবন্ধ যা দেখায় যে async অপেক্ষা করা ভাল প্রতিশ্রুতিগুলির উপর হ্যাকারুনুন.com/…
শুভম খাত্রি

টিউক
ম্যাডি

@ তিলকম্যাডি আপনি কেন ধরে নিয়েছেন যে প্রতিটি প্রতিক্রিয়া অ্যাপ্লিকেশন রিডেক্স ব্যবহার করে?
মিরাকুরুন

@ মীরকুরুন কেন পুরো স্ট্যাকের ওভারফ্লো অনুমান করেছিল যে আমি যখন দিনের সাথে ফিরে সরল জাভাস্ক্রিপ্ট প্রশ্ন জিজ্ঞাসা করতাম তখন আমি jQuery ব্যবহার করি?
তিলক ম্যাডি

উত্তর:


162

আসুন পার্থক্যগুলি নির্দেশ করে এবং এটি কীভাবে সমস্যা সৃষ্টি করতে পারে তা নির্ধারণ করে শুরু করা যাক।

এখানে অ্যাসিঙ্কের কোড এবং "সিঙ্ক" componentDidMount()জীবনচক্র পদ্ধতি:

// This is typescript code
componentDidMount(): void { /* do something */ }

async componentDidMount(): Promise<void> {
    /* do something */
    /* You can use "await" here */
}

কোডটি দেখে আমি নিম্নলিখিত পার্থক্যগুলি চিহ্নিত করতে পারি:

  1. দ্য asyncমূলশব্দ: টাইপ করা বিষয়, এই নিছক একটি কোড মার্কার হয়। এটি 2 টি কাজ করে:
    • রিটার্নের ধরণের Promise<void>পরিবর্তে চাপ দিনvoid । আপনি যদি স্পষ্টরূপে রিটার্নের ধরণটি অ-প্রতিশ্রুতিযুক্ত হিসাবে নির্ধারণ করেন (উদা: শূন্য), টাইপস্ক্রিপ্টটি আপনাকে একটি ত্রুটি ছুঁড়ে দেবে।
    • awaitপদ্ধতির অভ্যন্তরে কীওয়ার্ডগুলি ব্যবহার করার অনুমতি দিন ।
  2. রিটার্নের ধরণটি থেকে পরিবর্তিত voidহয়Promise<void>
    • এর অর্থ আপনি এখন এটি করতে পারেন:
      async someMethod(): Promise<void> { await componentDidMount(); }
  3. আপনি এখন awaitপদ্ধতির অভ্যন্তরে কীওয়ার্ডটি ব্যবহার করতে পারেন এবং অস্থায়ীভাবে এর প্রয়োগটি বিরতি দিতে পারেন। এটার মত:

    async componentDidMount(): Promise<void> {
        const users = await axios.get<string>("http://localhost:9001/users");
        const questions = await axios.get<string>("http://localhost:9001/questions");
    
        // Sleep for 10 seconds
        await new Promise(resolve => { setTimeout(resolve, 10000); });
    
        // This line of code will be executed after 10+ seconds
        this.setState({users, questions});
        return Promise.resolve();
    }

এখন তারা কীভাবে সমস্যা সৃষ্টি করতে পারে?

  1. দ্য asyncশব্দ একেবারে নিরীহ নয়।
  2. componentDidMount()রিটার্নের ধরণের ক্ষেত্রে আপনাকে যে পদ্ধতিতে কল করতে হবে তা আমি কল্পনা করতে পারি নাPromise<void> ধরণটিও নিরীহ is

    কীওয়ার্ড Promise<void>ছাড়াই রিটার্নের ধরণের পদ্ধতিতে কল করা কোনওর মতো রিটার্নের ধরণের ফোন করা awaitথেকে কোনও পার্থক্য রাখে না void

  3. যেহেতু কোনও জীবনচক্র পদ্ধতি নেই componentDidMount() কার্যকর বিলম্ব বেশ নিরাপদ বলে মনে হচ্ছে। তবে একটা গোটচা আছে।

    ধরা যাক, this.setState({users, questions});উপরেরটি 10 ​​সেকেন্ড পরে কার্যকর করা হবে। দেরি হওয়ার মাঝামাঝি সময়ে আরেকটি ...

    this.setState({users: newerUsers, questions: newerQuestions});

    ... সফলভাবে সম্পাদন করা হয়েছিল এবং ডিওএম আপডেট হয়েছিল। ফলাফলটি ব্যবহারকারীদের কাছে দৃশ্যমান ছিল। ঘড়িটি টিকটিকি অবিরত ছিল এবং 10 সেকেন্ড সময় কেটে গেছে। বিলম্বের this.setState(...)পরে কার্যকর করা হবে এবং DOM আবার আপডেট করা হবে, সেই সময় পুরানো ব্যবহারকারী এবং পুরানো প্রশ্নের সাথে। ফলাফলটি ব্যবহারকারীদের কাছেও দৃশ্যমান হবে।

=> এটি বেশ নিরাপদ ব্যবহার করবেন (আমি 100% নিশ্চিত নই) asyncসঙ্গে componentDidMount()পদ্ধতি। আমি এটির একটি বড় অনুরাগী এবং এখনও অবধি আমি এমন কোনও সমস্যার মুখোমুখি হইনি যা আমাকে খুব বেশি মাথা ব্যথা করে।


যখন আপনি এই সমস্যাটি নিয়ে কথা বলছেন যেখানে অন্য একটি সেটস্টেট একটি মুলতুবি প্রতিশ্রুতির আগে ঘটেছিল, তখন কি প্রতিশ্রুতির সাথে async / সিনট্যাকটিক চিনি বা এমনকি ক্লাসিক কলব্যাকের অপেক্ষা না করা একই নয়?
ক্লাফু

3
হ্যাঁ! setState()সর্বদা বিলম্ব করা একটি সামান্য ঝুঁকির মধ্যে রয়েছে। আমাদের যত্ন সহকারে এগিয়ে যাওয়া উচিত।
সিএ সি সি হিইউ

আমার ধারণা, সমস্যাগুলি এড়ানোর এক উপায় হ'ল isFetching: trueউপাদানটির রাজ্যের অভ্যন্তরের মতো কিছু ব্যবহার করা । আমি এটি কেবল রেডুএক্সের সাথেই ব্যবহার করেছি তবে আমি মনে করি এটি কেবলমাত্র বিক্রিয়া-সংক্রান্ত রাষ্ট্র পরিচালনার সাথে সম্পূর্ণ বৈধ। যদিও কোডটি অন্য কোথাও আপডেট করা একই রাজ্যের সমস্যাটির সমাধান করে না ...
ক্লাফু

1
আমি যে তার সাথে একমত. প্রকৃতপক্ষে, isFetchingপতাকাটির সমাধানটি বেশ সাধারণ, বিশেষত যখন আমরা সামনে-এন্ডে কিছু অ্যানিমেশন খেলতে চাই যখন ব্যাক-এন্ড প্রতিক্রিয়ার জন্য অপেক্ষা করি ( isFetching: true)।
Cù Đức Hiếu

3
আপনি যদি উপাদানটি আনমাউন্ট করার পরে সেট স্টেট না করেন তবে আপনি সমস্যার মধ্যে পড়তে পারেন
এলিয়েজার স্টেইনবক

18

2020 এপ্রিল আপডেট করুন: ইস্যুটি 16.13.1 এর সর্বশেষ প্রতিক্রিয়াতে স্থির হয়েছে বলে মনে হচ্ছে, এই স্যান্ডবক্সের উদাহরণটি দেখুন । এটি নির্দেশ করার জন্য @ আবার্নিয়ারকে ধন্যবাদ।


আমি কিছু গবেষণা করেছি এবং আমি একটি গুরুত্বপূর্ণ পার্থক্য খুঁজে পেয়েছি: প্রতিক্রিয়া অ্যাসিঙ্ক লাইফেসাইক্যাল পদ্ধতিগুলি থেকে ত্রুটিগুলি প্রক্রিয়া করে না।

সুতরাং, আপনি যদি এই জাতীয় কিছু লিখেন:

componentDidMount()
{
    throw new Error('I crashed!');
}

তারপরে আপনার ত্রুটিটি ত্রুটি সীমার দ্বারা ধরা পড়বে এবং আপনি এটি প্রক্রিয়া করতে পারেন এবং একটি দুর্দান্ত বার্তা প্রদর্শন করতে পারেন।

যদি আমরা কোডটি এর মতো পরিবর্তন করি:

async componentDidMount()
{
    throw new Error('I crashed!');
}

যা এর সমান:

componentDidMount()
{
    return Promise.reject(new Error('I crashed!'));
}

তাহলে আপনার ত্রুটি নিঃশব্দে গ্রাস করা হবে । আপনাকে লজ্জা, প্রতিক্রিয়া ...

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

async componentDidMount()
{
    try
    {
         await myAsyncFunction();
    }
    catch(error)
    {
        //...
    }
}

বা এই মত:

componentDidMount()
{
    myAsyncFunction()
    .catch(()=>
    {
        //...
    });
}

যদি আমরা এখনও আমাদের ত্রুটিটি ত্রুটির সীমানায় পৌঁছাতে চাই তবে আমি নিম্নলিখিত কৌশল সম্পর্কে ভাবতে পারি:

  1. ত্রুটিটি ধরুন, ত্রুটি হ্যান্ডলারটি উপাদানটির স্থিতি পরিবর্তন করুন
  2. রাষ্ট্র যদি কোনও ত্রুটি নির্দেশ করে তবে এটিকে renderপদ্ধতি থেকে ফেলে দিন

উদাহরণ:

class BuggyComponent extends React.Component {
  constructor(props) {
    super(props);
    this.state = { error: null };
  }

  buggyAsyncfunction(){ return Promise.reject(new Error('I crashed async!'));}

  async componentDidMount() {
    try
    {
      await this.buggyAsyncfunction();
    }
    catch(error)
    {
        this.setState({error: error});
    }
  }

  render() {
    if(this.state.error)
        throw this.state.error;

    return <h1>I am OK</h1>;
  }
}

এর জন্য কি কোনও সমস্যা আছে? তবুও যদি মামলা হয় তবে এটি প্রতিবেদন করার জন্য দরকারী হতে পারে ... thx
অ্যাবার্নিয়ার

@ বার্নিয়ার আমি মনে করি এটি বিনয়ের দ্বারা ... যদিও তারা সম্ভবত এটির উন্নতি করতে পারে। আমি এই সম্পর্কে কোনও সমস্যা দায়ের করি নি ...
সিএফ

1
এখানে আর পরীক্ষিত হিসাবে কমপক্ষে ১.1.১৩.১ এর প্রতিক্রিয়া রয়েছে বলে মনে হচ্ছে না: কোডস্যান্ডবক্স.আইও
বোল্ড-

9

আপনার কোডটি ভাল এবং আমার কাছে খুব পাঠযোগ্য। এই ডেল জেফারসনের নিবন্ধটি দেখুন যেখানে তিনি একটি অ্যাসিঙ্ক componentDidMountউদাহরণ দেখায় এবং সত্যিই দুর্দান্ত দেখায়।

তবে কিছু লোক বলবেন যে কোডটি পড়ছেন এমন একজন ব্যক্তি ধরে নিতে পারে যে প্রতিক্রিয়া প্রত্যাশিত প্রতিশ্রুতি দিয়ে কিছু করে।

সুতরাং এই কোডটির ব্যাখ্যা এবং যদি এটি একটি ভাল অনুশীলন হয় বা না হয় খুব ব্যক্তিগত।

আপনি যদি অন্য কোনও সমাধান চান তবে আপনি প্রতিশ্রুতি ব্যবহার করতে পারেন । উদাহরণ স্বরূপ:

componentDidMount() {
    fetch(this.getAuth())
      .then(auth => {
          if (auth) this.checkAuth(auth)
      })
}

3
... বা এছাড়াও, শুধু ভিতরে ভিতরে একটি ইনলাইন asyncফাংশন ব্যবহার করুন await...?
এরিক কাপলুন

@ এরিক অলিক :) এর একটি বিকল্প :)
টিয়াগো আলভেস

@ এরিক অলিক আপনার কি উদাহরণ রয়েছে?
পাবলো রিনকন

1
মত প্রস্তুত হত্তয়া @PabloRincon (async () => { const data = await fetch('foo'); const result = await submitRequest({data}); console.log(result) })()যেখানে fetchএবং submitRequestযে ফিরতি প্রতিশ্রুতি ফাংশন আছে।
এরিক কাপলুন

এই কোডটি অবশ্যই খারাপ, কারণ এটি getAuth কার্যক্রমে যে কোনও ত্রুটি ঘটেছে তা গ্রাস করবে। এবং যদি ফাংশনটি নেটওয়ার্কের সাথে কিছু করে (উদাহরণস্বরূপ), ত্রুটিগুলি অবশ্যই আশা করা উচিত।
সিএফ

6

আপনি কীওয়ার্ড componentDidMountছাড়াই ব্যবহার করেন async, ডকটি এটি বলে:

আপনি অবিলম্বে কম্পোনেন্টডিডমাউন্ট () এ সেট স্টেট () কল করতে পারেন। এটি একটি অতিরিক্ত রেন্ডারিং ট্রিগার করবে, তবে ব্রাউজারটি স্ক্রিন আপডেট করার আগে এটি ঘটবে।

আপনি যদি ব্যবহার করেন তবে async componentDidMountআপনি এই ক্ষমতাটি হ্রাস করবেন: ব্রাউজার আপডেট হওয়ার পরে অন্য একটি রেন্ডার ঘটবে। তবে ইমো, আপনি যদি ডেটা আনার মতো অ্যাসিঙ্ক ব্যবহার করার কথা ভাবছেন তবে আপনি এড়াতে পারবেন না যে ব্রাউজারটি দু'বার স্ক্রিন আপডেট করবে। অন্য একটি বিশ্বে ব্রাউজারটি স্ক্রিন আপডেট করার আগে PAUSE কম্পোনেন্টডিডমাউন্ট করা সম্ভব নয়


1
আমি এই উত্তরটি পছন্দ করি কারণ এটি সংক্ষিপ্ত এবং ডক্স দ্বারা সমর্থিত। আপনি যে দস্তাবেজগুলিতে উল্লেখ করছেন তা দয়া করে একটি লিঙ্ক যুক্ত করতে পারেন।
TheUiderSide

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

3

হালনাগাদ:

(আমার বিল্ড: প্রতিক্রিয়া 16, ওয়েবপ্যাক 4, বাবেল 7):

ব্যাবেল 7 ব্যবহার করার সময় আপনি আবিষ্কার করতে পারবেন:

এই নিদর্শনটি ব্যবহার করে ...

async componentDidMount() {
    try {
        const res = await fetch(config.discover.url);
        const data = await res.json();
        console.log(data);
    } catch(e) {
        console.error(e);
    }
}

আপনি নিম্নলিখিত ত্রুটি চালাবেন ...

আনকড রেফারেন্স এরিয়ার: রিজেনেটরআরটাইম সংজ্ঞায়িত হয়নি

এই ক্ষেত্রে আপনাকে ব্যাবেল-প্লাগইন-ট্রান্সফর্ম-রানটাইম ইনস্টল করতে হবে

https://babeljs.io/docs/en/babel-plugin-transform-runtime.html

যদি কোনও কারণে আপনি উপরের প্যাকেজটি ইনস্টল করতে চান না (বাবেল-প্লাগ-ইন-ট্রান্সফর্ম-রানটাইম) তবে আপনি প্রতিশ্রুতি রীতিতে আটকে থাকতে চাইবেন ...

componentDidMount() {
    fetch(config.discover.url)
    .then(res => res.json())
    .then(data => {
        console.log(data);
    })
    .catch(err => console.error(err));
}

3

আমি মনে করি এটি ঠিক আছে যতক্ষণ আপনি জানেন আপনি কী করছেন। তবে এটি বিভ্রান্তিকর হতে পারে কারণ async componentDidMount()চালানোর পরেও চলতে পারে componentWillUnmountএবং উপাদানটি আনমাউন্টে নেই।

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

আপনি async componentDidMount()বনাম সিঙ্ক componentDidMount()কলিং asyncপদ্ধতিগুলি চয়ন করুন না কেন , আপনাকে অবশ্যই নিশ্চিত করতে হবে যে আপনি যে কোনও শ্রোতা বা অ্যাসিঙ্ক পদ্ধতিগুলি অপসারণের পরেও চলতে পারে clean


2

প্রকৃতপক্ষে, কম্পোনেন্টডিডমাউন্টে অ্যাসিঙ্ক লোড করা একটি প্রস্তাবিত নকশার প্যাটার্ন হিসাবে প্রতিক্রিয়া হ'ল উত্তরাধিকারী জীবনচক্র পদ্ধতিগুলি (উপাদানবিহীনমাউন্ট, উপাদানবিট্রিলিপিস্রোপপ্রোপস, উপাদানবিঘা আপলোড) এবং অ্যাসিঙ্ক রেন্ডারিংয়ের দিকে চলে যায়।

এটি নিরাপদ কেন তা ব্যাখ্যা করতে এবং কম্পোনেন্টডিডমাউন্টে অ্যাসিঙ্ক লোডিংয়ের উদাহরণ সরবরাহ করতে এই ব্লগ পোস্টটি খুব সহায়ক:

https://reactjs.org/blog/2018/03/27/update-on-async-rendering.html


3
অ্যাসিঙ্ক রেন্ডারিংয়ের প্রকৃতপক্ষে স্পষ্টভাবে অ্যাসিঙ্কটি জীবনচক্র তৈরির সাথে সম্পর্কিত নয়। এটি আসলে একটি অ্যান্টি-প্যাটার্ন। প্রস্তাবিত সমাধানটি হ'ল একটি আজীবন পদ্ধতি থেকে অ্যাসিঙ্ক পদ্ধতিটি কল করা
ক্লেটন রে

1

আমি এই জাতীয় কিছু ব্যবহার করতে পছন্দ করি

componentDidMount(){
   const result = makeResquest()
}
async makeRequest(){
   const res = await fetch(url);
   const data = await res.json();
   return data
}
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.