প্রতিক্রিয়া - যখন প্যারেন্ট উপাদানগুলির সমস্ত উপ-উপাদান ব্যবহারকারীর কাছে দৃশ্যমান হয় তখন কীভাবে সনাক্ত করতে হয়?


11

টি এল; ডিআর

যখন তার অধীনে থাকা প্রতিটি সন্তানের উপাদানটির রেন্ডারিং শেষ হয়ে যায় এবং তার ডেম ব্যবহারকারীর কাছে তার সর্বোচ্চ আপ টু ডেট সংস্করণ থাকে তখন কীভাবে পিতা-মাতা উপাদান জানতে পারে?

আসুন ধরা যাক আমার একটি আছে component Aযাতে নাতি-নাতনী উপাদানগুলির Gridসমন্বয়ে একটি শিশু উপাদান রয়েছে 3x3। এই নাতি-নাতনী উপাদানগুলির প্রত্যেকটি একটি বিশ্রামপ্রাপ্ত এপিআই এন্ডপয়েন্ট থেকে ডেটা নিয়ে আসে এবং ডেটা উপলভ্য হলে নিজেকে রেন্ডার করে।

আমি Component Aএকটি loaderস্থানধারক দিয়ে পুরো অঞ্চলটি cover াকতে চাই, গ্রিডের উপাদানগুলির মধ্যে সর্বশেষটি যখন সাফল্যের সাথে ডেটা এনেছে এবং এটি উপস্থাপন করেছে কেবল তখনই উন্মোচন করা হবে, যেমন এটি ইতিমধ্যে ডোম-এ রয়েছে এবং এটি দেখা যেতে পারে।

ব্যবহারকারীর অভিজ্ঞতাটি ঝাঁকুনি ছাড়াই "লোডার" থেকে সম্পূর্ণ জনবহুল গ্রিডে সুপার মসৃণ রূপান্তর হওয়া উচিত।

আমার সমস্যাটি হ'ল লোডারটির নীচে থাকা উপাদানগুলি কখন উন্মোচন করতে হবে তা জানতে।

নিখুঁত নির্ভুলতার সাথে আমি এটি করতে নির্ভর করতে পারি এমন কোনও প্রক্রিয়া কি আছে? আমি লোডারের জন্য একটি নির্দিষ্ট সময়সীমা হার্ড কোড করতে চাই না। যেহেতু আমি বুঝতে পেরেছি ComponentDidMountপ্রতিটি সন্তানের জন্য নির্ভর করাও অবিশ্বাস্য কারণ এটি গ্যারান্টি দেয় না যে কলটির সময়টি উপাদানটি সম্পূর্ণরূপে দৃশ্যমান।

প্রশ্নটি আরও ছড়িয়ে দিতে:

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


রাষ্ট্র পরিচালনা করছেন কীভাবে? Redux ব্যবহার পছন্দ? বা এটি খাঁটি উপাদানগুলির সাথে যুক্ত হচ্ছে?
টেকটার্টেল

এটি উপাদানগুলির মধ্যে রয়েছে তবে বহিরাগত হতে পারে। আমি অন্যান্য জিনিসের জন্য রেডাক্স ব্যবহার করি।
জেসনজেনএক্স

এবং আপনি কীভাবে জানবেন যে গ্রিডের শেষ উপাদানটি ডেটা আনার কাজ শেষ করেছে?
টেকটার্টেল

আমি না। গ্রিড উপাদানগুলি একে অপর সম্পর্কে সচেতন নয়। প্রতিটি উপ-উপাদানগুলিতে ComponentDidMountআমি axiosডেটা আনতে ব্যবহার করছি । ডেটা যখন আসে তখন আমি সেই উপাদানটির অবস্থা পরিবর্তন করি যা ডেটা রেন্ডার করে। তত্ত্ব অনুসারে, 8 টি শিশু উপাদান 3 সেকেন্ডের মধ্যে আনতে পারে, এবং শেষটি 15 সেকেন্ড সময় নেয় ...
জেসনজেনএক্স

1
আমি এটি করতে পারি তবে আমি কীভাবে জানি যে কখন লোডার ওভারলেটি উন্মোচন করতে হয় যে ব্যবহারকারীরা কখনই দেখতে পাবে না যে কোনও উপাদান কীভাবে "খালি" থেকে "পূর্ণ" হয়? এটি ডেটা আনার প্রশ্ন নয়। এটি রেন্ডারিং সম্পর্কে ... এমনকি যদি আমার কেবল একটি সন্তানের উপাদান ছিল। কম্পোনেন্টডিডমাউন্ট যথেষ্ট নয়। পোস্ট-ডেটা-ফ্যাচিং-রেন্ডার কখন শেষ হয়েছে এবং DOM সম্পূর্ণ আপডেট হয়েছে যাতে আমি লোডার ওভারলেটি উন্মোচন করতে পারি তা আমার জানতে হবে।
জেসনজেনএক্স

উত্তর:


5

রিঅ্যাক্টে দুটি লাইফাইসাইকেল হুক রয়েছে যা একটি উপাদানগুলির ডিওএম রেন্ডার করার পরে ডাকা হয়:

আপনার ব্যবহার কেস জন্য আপনার পিতা বা মাতা উপাদান পি যখন আগ্রহী এন শিশু উপাদান প্রতিটি সন্তুষ্ট কিছু শর্ত আছে এক্স । এক্স ক্রম হিসাবে সংজ্ঞায়িত করা যেতে পারে:

  • অ্যাসিঙ্ক অপারেশন সম্পন্ন হয়েছে
  • উপাদান রেন্ডার হয়েছে

উপাদানটির রাজ্যের সংমিশ্রণ এবং componentDidUpdateহুক ব্যবহার করে আপনি জানতে পারবেন কখন অনুক্রমটি শেষ হয়েছে এবং আপনার উপাদানটি X এর শর্ত পূরণ করে

রাষ্ট্রীয় ভেরিয়েবল সেট করে আপনার অ্যাসিঙ্ক অপারেশন কখন শেষ হয়েছে তা আপনি ট্র্যাক রাখতে পারেন। উদাহরণ স্বরূপ:

this.setState({isFetched: true})

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

componentDidUpdate(_prevProps, prevState) {
  if (this.state.isFetched === true && this.state.isFetched !== prevState.isFetched) {
    this.props.componentHasMeaningfullyUpdated()
  }
}

আপনার পি উপাদানটিতে, কতগুলি বাচ্চা অর্থপূর্ণভাবে আপডেট হয়েছে তা ট্র্যাক রাখতে আপনি একটি কাউন্টার ব্যবহার করতে পারেন:

function onComponentHasMeaningfullyUpdated() {
  this.setState({counter: this.state.counter + 1})
}

অবশেষে, এন এর দৈর্ঘ্য জেনে আপনি জানতে পারবেন কখন সমস্ত অর্থবহ আপডেট হয়েছে এবং পি এর আপনার রেন্ডার পদ্ধতিতে সেই অনুযায়ী কাজ করতে পারেন :

const childRenderingFinished = this.state.counter >= N

1

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

আপনাকে আপনার এপিআই কলগুলি প্যারেন্ট পাত্রে স্থানান্তর করতে হবে Component A,। যদি আপনি কেবল এপিআই কলগুলি সম্পূর্ণ করার পরে আপনার নাতি-নাতনিদের রেন্ডার করতে চান তবে আপনি সেই এপিআই কলগুলি নাতি নাতনিদের কাছে রাখতে পারবেন না। এমন একটি উপাদান থেকে কীভাবে একটি এপিআই কল করা যেতে পারে যা এখনও বিদ্যমান নেই?

সমস্ত এপিআই কল হয়ে যাওয়ার পরে, আপনি একাধিক ডেটা অবজেক্ট সম্বলিত একটি বৈশ্বিক রাষ্ট্র পরিবর্তনশীল আপডেট করতে ক্রিয়াগুলি ব্যবহার করতে পারেন। প্রতিবার ডেটা পুনরুদ্ধার করা হয়েছে (বা একটি ত্রুটি ধরা পড়েছে), আপনার ডেটা অবজেক্টটি পুরোপুরি পূরণ হয়েছে কিনা তা পরীক্ষা করতে আপনি কোনও ক্রিয়া প্রেরণ করতে পারেন। এটি সম্পূর্ণরূপে পূরণ হয়ে গেলে, আপনি এর loadingপরিবর্তনশীল আপডেট করতে পারেন falseএবং শর্তসাপেক্ষে আপনার Gridউপাদানটি রেন্ডার করতে পারেন ।

উদাহরণস্বরূপ:

// Component A

import { acceptData, catchError } from '../actions'

class ComponentA extends React.Component{

  componentDidMount () {

    fetch('yoururl.com/data')
      .then( response => response.json() )
      // send your data to the global state data array
      .then( data => this.props.acceptData(data, grandChildNumber) )
      .catch( error => this.props.catchError(error, grandChildNumber) )

    // make all your fetch calls here

  }

  // Conditionally render your Loading or Grid based on the global state variable 'loading'
  render() {
    return (
      { this.props.loading && <Loading /> }
      { !this.props.loading && <Grid /> }
    )
  }

}


const mapStateToProps = state => ({ loading: state.loading })

const mapDispatchToProps = dispatch => ({ 
  acceptData: data => dispatch( acceptData( data, number ) )
  catchError: error=> dispatch( catchError( error, number) )
})
// Grid - not much going on here...

render () {
  return (
    <div className="Grid">
      <GrandChild1 number={1} />
      <GrandChild2 number={2} />
      <GrandChild3 number={3} />
      ...
      // Or render the granchildren from an array with a .map, or something similar
    </div>
  )
}
// Grandchild

// Conditionally render either an error or your data, depending on what came back from fetch
render () {
  return (
    { !this.props.data[this.props.number].error && <Your Content Here /> }
    { this.props.data[this.props.number].error && <Your Error Here /> }
  )
}

const mapStateToProps = state => ({ data: state.data })

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

// reducers.js

const initialState = {
  data: [{},{},{},{}...], // 9 empty objects
  loading: true
}

const reducers = (state = initialState, action) {
  switch(action.type){

    case RECIEVE_SOME_DATA:
      return {
        ...state,
        data: action.data
      }

     case RECIEVE_ERROR:
       return {
         ...state,
         data: action.data
       }

     case STOP_LOADING:
       return {
         ...state,
         loading: false
       }

  }
}

আপনার ক্রিয়ায়:


export const acceptData = (data, number) => {
  // First revise your data array to have the new data in the right place
  const updatedData = data
  updatedData[number] = data
  // Now check to see if all your data objects are populated
  // and update your loading state:
  dispatch( checkAllData() )
  return {
    type: RECIEVE_SOME_DATA,
    data: updatedData,
  }
}

// error checking - because you want your stuff to render even if one of your api calls 
// catches an error
export const catchError(error, number) {
  // First revise your data array to have the error in the right place
  const updatedData = data
  updatedData[number].error = error
  // Now check to see if all your data objects are populated
  // and update your loading state:
  dispatch( checkAllData() )
  return {
    type: RECIEVE_ERROR,
    data: updatedData,
  }
}

export const checkAllData() {
  // Check that every data object has something in it
  if ( // fancy footwork to check each object in the data array and see if its empty or not
    store.getState().data.every( dataSet => 
      Object.entries(dataSet).length === 0 && dataSet.constructor === Object ) ) {
        return {
          type: STOP_LOADING
        }
      }
  }

সরাইয়া

আপনি যদি এই ধারণাটির সাথে সত্যই বিবাহিত হন যে আপনার এপিআই কলগুলি প্রতিটি নাতি-নাতির মধ্যেই বাস করে, তবে সমস্ত এপিআই কল শেষ না হওয়া পর্যন্ত নাতি-নাতনির পুরো গ্রিডটি রেন্ডার করে না, আপনাকে একটি সম্পূর্ণ আলাদা সমাধান ব্যবহার করতে হবে। এই ক্ষেত্রে, আপনার নাতি নাতনিদের তাদের কল করার জন্য শুরু থেকেই রেন্ডার করতে হবে, তবে একটি সিএসএস ক্লাস থাকতে হবে display: none, যা কেবলমাত্র বিশ্বব্যাপী রাষ্ট্রের পরিবর্তনশীলকে loadingমিথ্যা হিসাবে চিহ্নিত করার পরে পরিবর্তিত হয় । এটি করণীয়ও, তবে প্রতিক্রিয়াটির দিক থেকেও বাছাই করা।


1

প্রতিক্রিয়া সাসপেন্স ব্যবহার করে আপনি সম্ভবত এটি সমাধান করতে পারেন ।

সতর্কবাণীটি হ'ল রেন্ডারকারী উপাদান উপাদানটি স্থগিত করা ভাল ধারণা নয় (এটি হ'ল: যদি আপনার উপাদানটি রেন্ডার প্রক্রিয়াটি সরিয়ে দেয় তবে আমার অভিজ্ঞতায় সেই উপাদানটি স্থগিত করা ভাল ধারণা নয়), তাই এটি সম্ভবত ভালো ধারণা উপাদান যে অনুরোধ বন্ধ লাথি উপস্থাপনা কোষ। এটার মতো কিছু:

export default function App() {
  const cells = React.useMemo(
    () =>
      ingredients.map((_, index) => {
        // This starts the fetch but *does not wait for it to finish*.
        return <Cell resource={fetchIngredient(index)} />;
      }),
    []
  );

  return (
    <div className="App">
      <Grid>{cells}</Grid>
    </div>
  );
}

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

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

অনুপস্থিত কোডের বাকি অংশটি এখানে:

const ingredients = [
  "Potato",
  "Cabbage",
  "Beef",
  "Bok Choi",
  "Prawns",
  "Red Onion",
  "Apple",
  "Raisin",
  "Spinach"
];

function randomTimeout(ms) {
  return Math.ceil(Math.random(1) * ms);
}

function fetchIngredient(id) {
  const task = new Promise(resolve => {
    setTimeout(() => resolve(ingredients[id]), randomTimeout(5000));
  });

  return new Resource(task);
}

// This is a stripped down version of the Resource class displayed in the React Suspense docs. It doesn't handle errors (and probably should).
// Calling read() will throw a Promise and, after the first event loop tick at the earliest, will return the value. This is a synchronous-ish API,
// Making it easy to use in React's render loop (which will not let you return anything other than a React element).
class Resource {
  constructor(promise) {
    this.task = promise.then(value => {
      this.value = value;
      this.status = "success";
    });
  }

  read() {
    switch (this.status) {
      case "success":
        return this.value;

      default:
        throw this.task;
    }
  }
}

function Cell({ resource }) {
  const data = resource.read();
  return <td>{data}</td>;
}

function Grid({ children }) {
  return (
    // This suspense boundary will cause a Loading sign to be displayed if any of the children suspend (throw a Promise).
    // Because we only have the one suspense boundary covering all children (and thus Cells), the fallback will be rendered
    // as long as at least one request is in progress.
    // Thanks to this approach, the Grid component need not be aware of how many Cells there are.
    <React.Suspense fallback={<h1>Loading..</h1>}>
      <table>{children}</table>
    </React.Suspense>
  );
}

এবং একটি স্যান্ডবক্স: https://codesandbox.io/s/falling-dust-b8e7s


1
শুধু মন্তব্যগুলি পড়ুন .. আমি বিশ্বাস করি না যে ডিওমে সমস্ত উপাদান রেন্ডার হওয়ার জন্য অপেক্ষা করা তুচ্ছ হবে - এবং এটি একটি ভাল কারণেই। মনে হচ্ছে যে খুব প্রকৃতপক্ষে hacky। আপনি কি অর্জন করার চেষ্টা করছেন?
ড্যান প্যান্ট্রি

1

প্রথমত, জীবন-চক্রের async / অপেক্ষার পদ্ধতি থাকতে পারে।

আমরা কি সম্পর্কে জানা প্রয়োজন componentDidMountএবং componentWillMount,

কম্পোনেন্ট উইলমাউন্টকে প্রথমে পিতা-মাতা এবং পরে শিশু বলা হয়।
কম্পোনেন্টডিডমাউন্ট বিপরীতে করুন।

আমার বিবেচনায়, কেবল সাধারণ জীবনচক্র ব্যবহার করে এগুলি প্রয়োগ করুন যথেষ্ট ভাল।

  • শিশু উপাদান
async componentDidMount() {
  await this.props.yourRequest();
  // Check if satisfied, if true, add flag to redux store or something,
  // or simply check the res stored in redux in parent leading no more method needed here
  await this.checkIfResGood();
}
  • মূল উপাদান
// Initial state `loading: true`
componentDidUpdate() {
  this.checkIfResHaveBad(); // If all good, `loading: false`
}
...
{this.state.loading ? <CircularProgress /> : <YourComponent/>}

উপাদান-ইউআই সার্কুলারপ্রসেস

যেহেতু শিশুদের পুনরায় রেন্ডারিংয়ের ফলে পিতামাতারা একই কাজ করে, তাই এটি ধরা didUpdateভাল।
এবং, যেহেতু এটি রেন্ডারিংয়ের পরে বলা হয়েছে, আপনি যদি চেক ফাংশনটিকে নিজের চাহিদা হিসাবে সেট করেন তবে পৃষ্ঠাগুলি পরিবর্তন করা উচিত নয়।

আমরা এই বাস্তবায়নটি আমাদের প্রোডে ব্যবহার করি যার একটি এপিআই রয়েছে যার ফলে 30 এর প্রতিক্রিয়া পাওয়া যায়, যতদূর আমি দেখছি সবই ভালভাবে কাজ করেছে।

এখানে চিত্র বর্ণনা লিখুন


0

আপনি componentDidMountযখন এপিআই কল করতে যাচ্ছেন , এপিআই কলটি সমাধান করবে তখন আপনার এই ডেটা থাকবে componentDidUpdateকারণ এই জীবনচক্রটি আপনাকে prevPropsএবং পাস করবে prevState। সুতরাং আপনি নীচের মতো কিছু করতে পারেন:

class Parent extends Component {
  getChildUpdateStatus = (data) => {
 // data is any data you want to send from child
}
render () {
 <Child sendChildUpdateStatus={getChildUpdateStatus}/>
}
}

class Child extends Component {
componentDidUpdate = (prevProps, prevState) => {
   //compare prevProps from this.props or prevState from current state as per your requirement
  this.props.sendChildUpdateStatus();
}

render () { 
   return <h2>{.. child rendering}</h2>
  }
}

আপনি যদি উপাদানটি রেন্ডার করার আগে এটি জানতে চান তবে আপনি ব্যবহার করতে পারেন getSnapshotBeforeUpdate

https://reactjs.org/docs/react-component.html#getsnapshotbeforeupdate


0

আপনি যেতে পারেন এমন একাধিক পদ্ধতি রয়েছে:

  1. সবচেয়ে সহজ উপায় হ'ল সন্তানের উপাদানগুলিতে একটি কলব্যাক পাস করা। এই শিশু উপাদানগুলি তখন তাদের ব্যক্তিগত ডেটা বা আপনি যে কোনও ব্যবসায়িক যুক্তি যুক্ত করতে চান তা আনার পরে রেন্ডার করার সাথে সাথে এই কলব্যাকটি কল করতে পারে। এটির জন্য এখানে একটি স্যান্ডবক্স রয়েছে: https://codesandbox.io/s/unruffled-shockley-yf3f3
  2. নির্ভরযোগ্য / শিশু উপাদানগুলি যখন কোনও গ্লোবাল অ্যাপ স্টেটে আনতে হবে সেগুলি ডেটা উপস্থাপনের সাথে সম্পন্ন হওয়ার পরে আপডেট করতে বলুন যা আপনার উপাদান শুনবে
  3. আপনি এই প্যারেন্ট উপাদানটির জন্য স্থানীয়করণ তৈরি করতে React.useContext ব্যবহার করতে পারেন। চাইল্ড উপাদানগুলি যখন এনে নেওয়া ডেটা রেন্ডারিংয়ের সাথে সম্পন্ন হয় তখন এই প্রসঙ্গটি আপডেট করতে পারে। আবার, প্যারেন্ট উপাদানগুলি এই প্রসঙ্গে শুনবে এবং সেই অনুযায়ী কাজ করতে পারে
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.