मैं आज reselect मिडलवेयर की कोशिश कर रहा हूं और अनावश्यक री-रेंडरिंग को रोक रहा हूं।

यहाँ मेरा reducer.js है:

const INITIAL_STATE = {
  dogs: 100,
  cats: 12312302384
};

const pets = (state = INITIAL_STATE, action) => {
  switch (action.type) {
    case "CHANGE_DOGS":
      return {
        ...state, dogs: state.dogs + 1
      };
    case "CHANGE_CATS":
      return {
        ...state, cats: state.cats + 1
      };
    default:
      return { ...state };
  }
};

export default pets;

यहाँ मेरा मुख्य जेएस है:

import React from "react";
import { createSelector } from "reselect";
import { useSelector, useDispatch } from "react-redux";

function ReduxDeneme(props) {
  // Selectors - Classic style - NON Memoized!
//   const dogsData = useSelector(state => state.pets.dogs);
//   const catsData = useSelector(state => state.pets.cats);

  //                          Dogs rendering..  --> First opening..
  // 10:11:28.070 index.js:18 CATS rendering.. --> First opening..
  // 10:11:29.703 index.js:13 Dogs rendering.. --> Press "ChangeDogs" button.
  // 10:11:29.703 index.js:18 CATS rendering..  --> Press "ChangeDogs" button.
  // 10:11:33.143 index.js:13 Dogs rendering.. --> Press "ChangeCats" button.
  // 10:11:33.143 index.js:18 CATS rendering..  --> Press "ChangeCats" button.

  // Selectors - Memoized version RESELECT middleware'i ile..
  const dogsDataMemo = createSelector(
    state => state.pets.dogs,
    dogs => dogs
  );
  const catsDataMemo = createSelector(
    state => state.pets.cats,
    cats => cats
  );

  const dogsData = useSelector(dogsDataMemo)
  const catsData = useSelector(catsDataMemo)


  // Components
  const Dogs = ({ dogsData }) => {
    console.log("Dogs rendering..");
    return <h1>{dogsData}</h1>;
  };

  const Cats = ({ catsData }) => {
    console.log("Cats rendering..");
    return <h1>{catsData}</h1>;
  };

  // Actions

  const dispatch = useDispatch();
  const changeDogs = () => dispatch({ type: "CHANGE_DOGS" });
  const changeCats = () => dispatch({ type: "CHANGE_CATS" });

  return (
    <div>
      <Dogs dogsData={dogsData} />
      <Cats catsData={catsData} />
      <button onClick={changeDogs}>Change Dogs</button>
      <button onClick={changeCats}>Change CATS</button>
    </div>
  );
}

export default ReduxDeneme;
  • <मजबूत>1. परिदृश्य: मैंने क्लासिक, गैर-यादगार शैली चयनकर्ताओं का उपयोग किया है। कंसोल पर 6 बार कंसोल.लॉग हैं। (पहले खुलने पर 2 बार - यह सामान्य है - 2 बार "कुत्ते बदलें" बटन पर क्लिक करने पर, 2 बार "बिल्लियों को बदलें" बटन पर क्लिक करने पर)। इसका मतलब है कि 6 बार री-रेंडरिंग हुई।
  • <मजबूत>2. परिदृश्य: मैंने अनावश्यक पुन: प्रतिपादन को रोकने के लिए reselect मिडलवेयर का उपयोग किया है। लेकिन, यह काम नहीं करता है या मैंने reselect का अर्थ गलत समझा है।

क्या कोई सही तरीका समझा सकता है या मैं कहाँ गलत कर रहा हूँ?

0
John Valdetine 16 मार्च 2020, 10:47
मेरा अनुमान है कि यह इसलिए है क्योंकि आप प्रत्येक रेंडर चक्र को पुनर्चयनित करने वाले चयनकर्ता को फिर से परिभाषित करते हैं, जो संभवत: useSelector हुक को ट्रिगर करता है, जो फिर उन घटकों के लिए सहारा के रूप में पारित बिल्लियों और कुत्तों के लिए नया संदर्भ लौटाता है, इस प्रकार वे पुन: प्रस्तुत करते हैं।
 – 
Drew Reese
16 मार्च 2020, 10:51

2 जवाब

आप अपने घटक के अंदर चयनकर्ताओं को परिभाषित कर रहे हैं। आपको इसे बाहर करना चाहिए (उदाहरण के लिए आपके रेड्यूसर के पास कहीं)।

वर्तमान में आप प्रत्येक रेंडर के बाद चयनकर्ता को फिर से बना रहे हैं। यहाँ एक बेहतर तरीका है:

// inside reducer.js

  export const petsSel = state => state.pets;
  export const dogsDataMemo = createSelector(
    petsSel,
    pets => pets.dogs
  );
  export const catsDataMemo = createSelector(
    petsSel,
    pets => pets.cats
  );

आपके कोड के आधार पर एक कार्यशील उदाहरण के साथ एक कोडसैंडबॉक्स जोड़ा गया: https://codesandbox.io/s/ नाजुक-स्नोफ्लेक-5ssrw

आप जो चाहते हैं उसे प्राप्त करने के लिए आपको React.memo (https://reactjs.org का उपयोग करने की आवश्यकता है। /docs/react-api.html#reactmemo) भी:

const Dogs = React.memo(({ dogsData }) => {
  console.log("Dogs rendering..");
  return <h1>{dogsData}</h1>;
});
1
tudor.gergely 16 मार्च 2020, 11:31
इनपुट चयनकर्ताओं को विभाजित करने के लिए +1। (लेकिन यह वह पैटर्न है जो reselect अपने दस्तावेज़ों में वैसे भी उपयोग करता है)
 – 
Drew Reese
16 मार्च 2020, 10:58
आपके सुझाव के लिए धन्यवाद लेकिन यह काम नहीं करता है। यह अभी भी फिर से प्रस्तुत करना जारी है। क्या आप कृपया विस्तार से समझाने के लिए मेरे कोड ठीक कर सकते हैं?
 – 
John Valdetine
16 मार्च 2020, 11:19
@tudor.gergely मैंने Cats और Dogs घटक को ReduxDeneme घटक के बाहर स्थानांतरित कर दिया है। जब हम memo के साथ Cats और Dogs कंपोनेंट बनाते हैं, तो यह बिना किसी अनावश्यक री-रेंडरिंग के काम करता है। लेकिन, मुझे लगता है कि यह सब memo के बारे में है। मैं reselect लाभ कैसे दिखा सकता हूं? मुझे लगा कि हम केवल reselect के साथ पुन: प्रस्तुत करने से रोक सकते हैं। अगर यह संभव है, तो क्या आप मुझे reselect काम करते हुए दिखा सकते हैं?
 – 
John Valdetine
16 मार्च 2020, 12:02
जब आप derived डेटा की पुनर्गणना करना चाहते हैं तो पुनर्चयन उपयोगी होता है: डेटा जो सीधे रेडक्स में संग्रहीत नहीं होता है लेकिन उस पर निर्भर करता है। यह केवल चयनकर्ता को फिर से गणना करके काम करता है जब उसका चयनकर्ता बदलता है (क्रिएटसेलेक्टर के अंदर पहला कार्य)। आप जो हासिल करना चाहते हैं, उसे भी React.memo की आवश्यकता है (अन्यथा रिएक्ट हमेशा पुन: प्रस्तुत करेगा)
 – 
tudor.gergely
16 मार्च 2020, 12:10
मैंने पूरा जवाब जोड़ा। आपके प्रयास के लिए धन्यवाद @tudor.gergely!
 – 
John Valdetine
16 मार्च 2020, 14:06

सबसे पहले, मैं @tudor को उनके प्रयासों के लिए बहुत-बहुत धन्यवाद देता हूं। उनकी कही हर बात सही है।

लेकिन, मैं दिखाना चाहता हूं कि Reselect काम करता है।

परिदृश्य 1 - याद नहीं किया गया

import React, { memo } from "react";
import { useSelector, useDispatch } from "react-redux";
// import { catsDataMemo, dogsDataMemo } from "./selectors";

// Components
const Dogs = memo(({ dogsData }) => {
  console.log("Dogs rendering..");
  return <h1>{dogsData}</h1>;
});

const Cats = memo(({ catsData }) => {
  console.log("Cats rendering..");
  return <h1>{catsData}</h1>;
});

function ReduxDeneme() {
  // Standart useSelector without MEMOIZED
  const dogsData = useSelector(
    state => state.pets.dogs,
    console.log("dogsData Selector çalıştı.")
  );
  const catsData = useSelector(
    state => state.pets.cats,
    console.log("catsData Selector çalıştı.")
  );

  // Actions

  const dispatch = useDispatch();
  const changeDogs = () => dispatch({ type: "CHANGE_DOGS" });
  const changeCats = () => dispatch({ type: "CHANGE_CATS" });

  const noChangeCats = () =>
    dispatch({ type: "NO_CHANGE_CATS", payload: catsData });

  return (
    <div>
      <Dogs dogsData={dogsData} />
      <Cats catsData={catsData} />
      <button onClick={changeDogs}>Change Dogs</button>
      <button onClick={changeCats}>Change CATS</button>
      <button onClick={noChangeCats}>No Change</button>
    </div>
  );
}

export default memo(ReduxDeneme);

सावधान रहें! जब आप "कुत्ते बदलें" बटन क्लिक करते हैं, तो कंसोल में आउटपुट होगा:

dogsData Selector çalıştı.
catsData Selector çalıştı.
Dogs rendering..

या जब आप "बिल्लियों को बदलें" बटन पर क्लिक करते हैं, तो आउटपुट होगा:

dogsData Selector çalıştı.
catsData Selector çalıştı.
Cats rendering..

आप जो भी बटन दबाते हैं, दोनों उपयोग चयनकर्ता काम करेंगे जैसा कि आप कंसोल से देख सकते हैं

परिदृश्य 2 - पुनः चयनित मिडलवेयर के साथ याद किया गया

सबसे पहले, हम याद किए गए चयनकर्ताओं को @tudor.gergely उल्लेख के अनुसार दूसरी फ़ाइल में अलग करते हैं।

सावधान रहें! आपको किसी वस्तु के सही पथ को परिभाषित करना होगा।

// selectors.js

import { createSelector } from "reselect";

export const dogsDataMemo = createSelector(
  state => state.pets.dogs, // BE CAREFULL while defining..
  dogs => {
    console.log("DogsDataMemo has worked.");
    return dogs;
  }
);
export const catsDataMemo = createSelector(
  state => state.pets.cats, // BE CAREFULL while defining..
  cats => {
    console.log("CatsDataMemo has worked.");
    return cats;
  }
);

फिर, हम इस फ़ाइल को main.js फ़ाइल में आयात करते हैं और हमारे यादगार चयनकर्ताओं के साथ फिर से useSelector का उपयोग करते हैं:

import React, { memo } from "react";
import { useSelector, useDispatch } from "react-redux";
import { catsDataMemo, dogsDataMemo } from "./selectors";

// Components
const Dogs = memo(({ dogsData }) => {
  console.log("Dogs rendering..");
  return <h1>{dogsData}</h1>;
});

const Cats = memo(({ catsData }) => {
  console.log("Cats rendering..");
  return <h1>{catsData}</h1>;
});

function ReduxDeneme() {
  const dogsData = useSelector(dogsDataMemo);
  const catsData = useSelector(catsDataMemo);

  // Actions
  const dispatch = useDispatch();
  const changeDogs = () => dispatch({ type: "CHANGE_DOGS" });
  const changeCats = () => dispatch({ type: "CHANGE_CATS" });

  const noChangeCats = () =>
    dispatch({ type: "NO_CHANGE_CATS", payload: catsData });

  return (
    <div>
      <Dogs dogsData={dogsData} />
      <Cats catsData={catsData} />
      <button onClick={changeDogs}>Change Dogs</button>
      <button onClick={changeCats}>Change CATS</button>
      <button onClick={noChangeCats}>No Change</button>
    </div>
  );
}

export default memo(ReduxDeneme);

और अंतिम आउटपुट:

  • "कुत्ते बदलें" बटन पर क्लिक करें:
DogsDataMemo has worked.
Dogs rendering
  • जब "बिल्लियाँ बदलें" बटन पर क्लिक करें:
CatsDataMemo has worked.
Cats rendering..
1
John Valdetine 16 मार्च 2020, 14:03
आपको वास्तव में चयनकर्ता का उपयोग पहचान फ़ंक्शन (कुत्तों => कुत्तों) के साथ नहीं करना चाहिए क्योंकि यह वास्तव में मदद नहीं करता है। व्युत्पन्न डेटा के लिए पुनर्चयन उपयोगी है, जैसा कि उनकी वेबसाइट पर उल्लेख किया गया है।
 – 
tudor.gergely
16 मार्च 2020, 17:52
बुनियादी पहचान कार्यों के लिए पुन: चयन करने के बजाय उपयोग करने के लिए आपका क्या सुझाव है?
 – 
John Valdetine
16 मार्च 2020, 22:03