Как предотвратить повторную визуализацию с повторным выбором? - PullRequest
0 голосов
/ 16 марта 2020

Я пытаюсь reselect промежуточного программного обеспечения сегодня и предотвратить ненужный повторный рендеринг.

Вот мой редуктор. 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;

Вот мой основной. js:

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. Сценарий : я использовал classi c, незапоминающиеся селекторы стилей. На консоли есть 6 раз console.log. (2 раза при первом открытии - это нормально - 2 раза при нажатии кнопки «Сменить собаку», 2 раза при нажатии кнопки «Смена кошки»). Это означает, что 6 раз произошел повторный рендеринг.
  • 2. Сценарий : я использовал промежуточное ПО reselect для предотвращения ненужных повторных рендерингов. Но, это не работает, или я неправильно понял значение reselect.

Может кто-нибудь объяснить правильный путь или где я делаю неправильно?

Ответы [ 2 ]

1 голос
/ 16 марта 2020

Вы определяете селекторы внутри вашего компонента. Вы должны сделать это снаружи (например, где-то рядом с вашим редуктором).

В настоящее время вы воссоздаете селектор после каждого рендера. Вот лучший способ:

// 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/delicate-snowflake-5ssrw

Чтобы достичь того, что вы хотите, вам нужно использовать React.memo (https://reactjs.org/docs/react-api.html#reactmemo), а также:

const Dogs = React.memo(({ dogsData }) => {
  console.log("Dogs rendering..");
  return <h1>{dogsData}</h1>;
});
0 голосов
/ 16 марта 2020

Прежде всего, я благодарю @tudor за его усилия. Все его слова верны.

Но я хочу показать, что Реселект работает.

СЦЕНАРИЙ 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);

Будьте осторожны! Когда вы нажимаете кнопку " Change Dogs ", в консоли выводится:

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

или когда вы нажимаете " Кнопка Change Cats", на выходе будет:

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

. Независимо от того, какую кнопку вы нажмете, оба из useSelectors будут работать, как вы можете видеть из console.log

SCENARIO 2 - MEMOIZED С ПОМОЩЬЮ СРЕДНЕГО ОБЕСПЕЧЕНИЯ

Во-первых, мы выделяем запомненные селекторы для другого файла, как упоминалось @ 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;
  }
);

Затем мы импортируем этот файл в основной файл. 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..
...