Как Redux Reselect работает с памяткой? - PullRequest
0 голосов
/ 02 октября 2018

Я пытаюсь интегрировать reselect в мое текущее приложение и, как всегда, сначала я начинаю читать документацию, а затем, если это необходимо, другие источники. Я не мог понять одну особенную часть документации и также не мог найтиисточники, которые объяснили бы более ясным способом. Теперь я здесь, чтобы получить некоторое ясное объяснение.Так сказано в документации `

import React from 'react'
import Footer from './Footer'
import AddTodo from '../containers/AddTodo'
import VisibleTodoList from '../containers/VisibleTodoList'

const App = () => (
  <div>
    <VisibleTodoList listId="1" />
    <VisibleTodoList listId="2" />
    <VisibleTodoList listId="3" />
  </div>
)

Использование селектора getVisibleTodos с несколькими экземплярами контейнера VisibleTodoList не будет правильно запоминать:

import { connect } from 'react-redux'
import { toggleTodo } from '../actions'
import TodoList from '../components/TodoList'
import { getVisibleTodos } from '../selectors'

const mapStateToProps = (state, props) => {
  return {
    // WARNING: THE FOLLOWING SELECTOR DOES NOT CORRECTLY MEMOIZE
    todos: getVisibleTodos(state, props)
  }
}

const mapDispatchToProps = (dispatch) => {
  return {
    onTodoClick: (id) => {
      dispatch(toggleTodo(id))
    }
  }
}

const VisibleTodoList = connect(
  mapStateToProps,
  mapDispatchToProps
)(TodoList)

export default VisibleTodoList

AСелектор, созданный с помощью createSelector, имеет размер кэша 1 и возвращает кэшированное значение только тогда, когда его набор аргументов совпадает с его предыдущим набором аргументов.Если мы чередуем рендеринг <VisibleTodoList listId="1" /> и <VisibleTodoList listId="2" />, общий селектор будет чередоваться между получением {listId: 1} и {listId: 2} в качестве аргумента props.Это приведет к тому, что аргументы будут разными при каждом вызове, поэтому селектор всегда будет пересчитывать, а не возвращать кэшированное значение.

Обратите внимание на последнее предложение.Зачем возвращать кэшированное значение, если мы передаем разные значения id s, и оно должно возвращать нам разные значения, зависит от id s?

Ответы [ 2 ]

0 голосов
/ 30 октября 2018

Итак, у нас есть селектор, который получает состояние для нашего VisibleTodoList компонента:

const mapStateToProps = (state, props) => {
  return {
    todos: getVisibleTodos(state, props)
  }
}

Если мы отрендерим компонент:

return (
    <div>
        <VisibleTodoList listId="1" />
    </div>
)

Затем селектор будет вызываться так: getVisibleTodos(state, { listId: 1 }), и селектор сохраняет (запоминает) результат (объект списка задач 1) в памяти.

Если мы визуализируем компонент дважды с одинаковыми реквизитами:

return (
    <div>
        <VisibleTodoList listId="1" />
        <VisibleTodoList listId="1" />
    </div>
)
  1. селектор вызывается и результат запоминается

  2. селектор вызывается во второй раз, и он видит, что { listId: 1 } - это те же аргументы проп, что и в первый раз, поэтомупросто возвращает запомненное значение.

Если мы дважды визуализируем компонент с разными реквизитами:

return (
    <div>
        <VisibleTodoList listId="1" />
        <VisibleTodoList listId="2" />
    </div>
)
  1. , вызывается селектор, и результатзапоминается

  2. селектор вызывается второй раз, и он видит, что { listId: 2 } - это не те же аргументы, что и в первый раз { listId: 1 }, поэтому он пересчитывает и запоминает новоерезультат (список задач 2 объекта) в памяти (перезаписывая предыдущий мемоизатion).

Если мы хотим, чтобы каждый компонент получал свою собственную памятку, каждый экземпляр компонента должен иметь свой собственный экземпляр селектора.

Например:

// selector
const makeGetVisibleTodos = () => createSelector(
    // ... get the visible todos
);

// each has their own memoization space:
const foo = makeGetVisibleTodos(); // this is an instance
const bar = makeGetVisibleTodos(); // this is a separate instance

Таким образом, применяя его к компоненту:

// component
const mapStateToProps = () => {
    const getVisibleTodos = makeGetVisibleTodos(); // this instance get bound to the component instance

    return (state, props) => {
        return {
            todos: getVisibleTodos(state, props)
        }   
    }
}

Теперь, если мы визуализируем компонент дважды с разными реквизитами:

return (
    <div>
        <VisibleTodoList listId="1" />
        <VisibleTodoList listId="2" />
    </div>
)
  1. с <VisibleTodoList listId="1" /> вызывается первый экземпляр селектора, и результат запоминается

  2. с <VisibleTodoList listId="2" /> вызывается другой экземпляр селектора, и результат запоминается

0 голосов
/ 02 октября 2018

Нет, это не возвращает неправильное значение.Документация просто говорит, что для этого случая запоминание не будет работать вообще.Чтобы заставить его работать (в смысле «сохранить некоторые ресурсы и избегать повторения одного и того же вычисления»), вам нужно.

На самом деле документ говорит (последнее предложение в цитируемом вами разделе):

Мы увидим, как преодолеть это ограничение в следующем разделе.

И следующий раздел Совместное использование селекторов с подпорками в нескольких компонентах говорит

Чтобы разделить селектор между несколькими экземплярами VisibleTodoList, передавая реквизиты и сохраняя памятку, каждому экземпляру компонента требуется своя собственная копия селектора.

Также вы можетеувеличьте размер напоминания до 1.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...