Может кто-нибудь объяснить, как функции ввода используются в функциях в библиотеке повторного выбора? - PullRequest
1 голос
/ 28 октября 2019

https://github.com/reduxjs/reselect/blob/master/src/index.js#L89

export function defaultMemoize(func, equalityCheck = defaultEqualityCheck) {
  let lastArgs = null
  let lastResult = null
  // we reference arguments instead of spreading them for performance reasons
  return function () {
    if (!areArgumentsShallowlyEqual(equalityCheck, lastArgs, arguments)) {
      // apply arguments instead of spreading for performance.
      lastResult = func.apply(null, arguments)
    }

    lastArgs = arguments
    return lastResult
  }
}

export function createSelectorCreator(memoize, ...memoizeOptions) {
  return (...funcs) => {
    let recomputations = 0
    const resultFunc = funcs.pop()
    const dependencies = getDependencies(funcs)

    const memoizedResultFunc = memoize(
      function () {
        recomputations++
        // apply arguments instead of spreading for performance.
        return resultFunc.apply(null, arguments)
      },
      ...memoizeOptions
    )
...}
}


export const createSelector = createSelectorCreator(defaultMemoize)

Так что, если я создам createSelector(getUsers, (users) => users) для создания простого примера. Как это работает с кодами сверху?

createSelectorCreator(defaultMemoize) вызывается с getUsers, (users) => users входами. Теперь defaultMemoize также является функцией, которая возвращает функцию. Как все они взаимодействуют, чтобы вернуть значение?

1 Ответ

0 голосов
/ 28 октября 2019

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

Композиционность

Еще один способ сказать, что вы пишете селектор один раз и повторно используете его в других более детальных селекторах. Допустим, у меня есть состояние, подобное этому: {data:{people:[person,person ...]} Тогда я могу написать filterPerson следующим образом:

const selectData = state => state.data;
const selectDataEntity = createSelector(
  selectData,//re use selectData
  (_, entity) => entity,
  (data, entity) => data[entity]
);
const filterDataEntity = createSelector(
  selectDataEntity,//re use selectDataEntity
  (a, b, filter) => filter,
  (entities, filter) => entities.filter(filter)
);

Если я переместу данные в state.apiResult, тогда мне нужно только изменить selectData, это максимизируетповторное использование кода и сводит к минимуму дублирование реализации.

Запоминание

Запоминание означает, что при многократном вызове функции с одинаковыми аргументами функция будет выполнена только один раз,Чистые функции возвращают один и тот же результат с одинаковыми аргументами независимо от того, сколько раз они были вызваны или когда они вызываются.

Это означает, что вам не нужно выполнять функцию при повторном вызове с теми же параметрами, поскольку вы уже знаете результат.

Запоминание можно использовать, чтобы не вызывать дорогие функции (как фильтрация большого массива). В React запоминание важно, потому что чистые компоненты будут визуализироваться при смене реквизита:

const mapStateToProps = state => {
  //already assuming where data is and people is not
  //  a constant
  return {
    USPeople: state.data.people.filter(person=>person.address.countey === US)
  }
}

Даже если state.data.people не изменил, функция фильтра каждый раз будет возвращать новый массив.

Как это работает

Ниже приведена перезапись createSelector с некоторыми комментариями. Удален некоторый код, который проверял бы параметры безопасности и позволял бы вам вызывать createSelector с массивом функций. Пожалуйста, прокомментируйте, если есть что-то, что вам трудно понять.

const memoize = fn => {
  let lastResult,
    //initial last arguments is not going to be the same
    //  as anything you will pass to the function the first time
    lastArguments = [{}];
  return (...currentArgs) => {//returning memoized function
    //check if currently passed arguments are the same as
    //  arguments passed last time
    const sameArgs =
      currentArgs.length === lastArguments.length &&
      lastArguments.reduce(
        (result, lastArg, index) =>
          result && Object.is(lastArg, currentArgs[index]),
        true
      );
    if (sameArgs) {
      //current arguments are same as last so just
      //  return the last result and don't execute function
      return lastResult;
    }
    //current arguments are not the same as last time
    //  or function called for the first time, execute the
    //  function and set last result
    lastResult = fn.apply(null, currentArgs);
    //set last args to current args
    lastArguments = currentArgs;
    //return result
    return lastResult;
  };
};

const createSelector = (...functions) => {
  //get the last function by popping it off of functions
  //  this mutates functions so functions does not have the
  //  last function on it anymore
  //  also memoize the last function
  const lastFunction = memoize(functions.pop());
  //return a selector function
  return (...args) => {
    //execute all the functions (last was already removed)
    const argsForLastFunction = functions.map(fn =>
      fn.apply(null, args)
    );
    //return the result of a call to lastFunction with the
    //  result of the other functions as arguments
    return lastFunction.apply(null, argsForLastFunction);
  };
};
//selector to get data from state
const selectData = state => state.data;
//select a particular entity from state data
//  has 2 arguments: state and entity where entity
//  is a string (like 'people')
const selectDataEntity = createSelector(
  selectData,
  (_, entity) => entity,
  (data, entity) => data[entity]
);
//select an entity from state data and filter it
//  has 3 arguments: state, entity and filterFunction
//  entity is string (like 'people') filter is a function like:
//  person=>person.address.country === US
const filterDataEntity = createSelector(
  selectDataEntity,
  (a, b, filter) => filter,
  (entities, filter) => entities.filter(filter)
);
//some constants
const US = 'US';
const PEOPLE = 'people';
//the state (like state from redux in connect or useSelector)
const state = {
  data: {
    people: [
      { address: { country: 'US' } },
      { address: { country: 'CA' } },
    ],
  },
};
//the filter function to get people from the US
const filterPeopleUS = person =>
  person.address.country === US;
//get people from the US first time
const peopleInUS1 = filterDataEntity(
  state,
  PEOPLE,
  filterPeopleUS
);
//get people from the US second time
const peopleInUS2 = filterDataEntity(
  state,
  PEOPLE,
  filterPeopleUS
);

console.log('people in the US:', peopleInUS1);
console.log(
  'first and second time is same:',
  peopleInUS1 === peopleInUS2
);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...