为什么此重新选择选择器会导致重新渲染?

时间:2020-05-08 12:41:04

标签: reactjs redux reselect

我的一个组件正在重新渲染,我意识到这是因为下面的allPageViews选择器:

const getPages = (state: IAppState) => {
  return state.pages;
};


export const attachPageViews = createSelector(
  getPages,
  (pages) => pages.pageViews
);
export const selectPageViews = createSelector(
  attachPageViews,
  (pageViews) => pageViews
);


export const allPageViews = createSelector(
  selectPageViews,
  (pageStore: PageViewStore) => {
    let returnedPageViews: PageView[] = [];
    for (const section of Object.values(pageStore.sections)) {
      for (const page of Object.values(section!.pageViews)) {
        returnedPageViews = [...returnedPageViews, page!];
      }
    }
    return returnedPageViews;
  }
);

当我调度一个动作时,我在更改页面缩减器,但不更改其中包含的pageViews(页面具有另一个称为数据的键,我正在更新)。因此,根据我的理解,selectPageViews不应更改(因为基础的pageViews不会更改),因此allPageViews应该只是存储而不是重新计算,因为没有任何更新。

尽管如此,它仍在重新计算。当我将returnPageViews数组和for循环移到使用useSelector()的组件中时,该组件停止了重新渲染。

所以我的问题是-重新选择是如何工作的,为什么要在allPageViews中创建数组时重新选择并触发重新渲染?

2 个答案:

答案 0 :(得分:0)

我正在更改页面精简器,但没有更改其中包含的pageViews(页面有另一个名为我正在更新的数据的键)。因此,根据我的理解,selectPageViews不应更改(因为基础的pageViews不会更改),因此allPageViews应该只是记录性的,而不是因为没有任何更新而重新计算。

没错,state.page.pageViews并未更改,因此selectPageViews将返回记录的结果,而allPageViews也将返回。

尽管如此,它仍在重新计算。当我将returnPageViews数组和for循环移到使用useSelector()的组件中时,该组件停止了重新呈现。所以我的问题是-当在allPageViews中创建数组时,Reselect如何工作,为什么它会重新计算并触发重新渲染

那没有意义,所以选择器不是在触发重新渲染吗? Nonetheless it was re-calculating是不正确的,这是下面的代码,表明您的最初假设是正确的;如果您不更改state.page.pageViews,则selectPageViews和allPageViews都将返回其记忆的结果(不会重新计算):

const { createSelector } = Reselect;
const getPages = (state) => {
  return state.pages;
};

const attachPageViews = createSelector(
  getPages,
  (pages) => pages.pageViews
);
//this one is kind of useless, it does x=>x so you may as
//  well do: const selectPageViews = attachPageViews
const selectPageViews = createSelector(
  attachPageViews,
  (pageViews) => {
    console.log(
      'selectPageViews logs once but is called twice'
    );
    return pageViews;
  }
);

const allPageViews = createSelector(
  selectPageViews,
  (pageStore) => {
    console.log(
      'allPageViews logs once but is called twice'
    );
    return { new: 'object', pageStore };
  }
);
const state = {
  pages: {
    pageViews: { value: 'this is page views' },
  },
};
console.log('calling allPageViews first time');
const one = allPageViews(state);
console.log('calling allPageViews second time with changed state.pages');
const two = allPageViews({
  ...state,
  pages: {
    ...state.pages,
    changedSomething: true,
  },
});
console.log('both results are the same:',one === two);
<script src="https://cdnjs.cloudflare.com/ajax/libs/reselect/4.0.0/reselect.min.js"></script>


<div id="root"></div>

答案 1 :(得分:0)

根据我的经验,当side createSelector中的任何依赖项重新计算时,它将重新渲染,例如

 const dep2 = createSelector(
    dep4,
    dep5,
    (a, b) => a * b;
   dep1,
   dep2,
   dep3,
   (a, b, c) => d

每当计算d2时,最后一个就会重新计算