有人可以解释如何在重新选择库的函数中使用输入函数吗?
Can someone explain how input functions are used in functions in reselect library?
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
也是一个函数,return是一个函数。他们如何与 return 价值互动?
我认为对于重新选择的工作方式更重要的是为什么要使用它。主要原因是可组合性和记忆化:
可组合性
另一种说法是,您编写一次选择器,然后在其他更详细的选择器中重新使用它。假设我有一个这样的状态:{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
,这会最大限度地重复使用代码并最大限度地减少重复实现。
记忆
记忆化意味着当你用相同的参数多次调用一个函数时,该函数只会执行一次。纯函数 return 无论调用多少次或何时调用,给定相同参数的结果相同。
这意味着当您使用相同的参数再次调用它时不需要执行该函数,因为您已经知道结果。
Memoization 可用于不调用昂贵的函数(如过滤大型数组)。在 React 中,记忆很重要,因为如果 props 发生变化,纯组件将重新渲染:
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
没有改变过滤器函数每次都会 return 一个新数组。
工作原理
下面是对 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
);
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
也是一个函数,return是一个函数。他们如何与 return 价值互动?
我认为对于重新选择的工作方式更重要的是为什么要使用它。主要原因是可组合性和记忆化:
可组合性
另一种说法是,您编写一次选择器,然后在其他更详细的选择器中重新使用它。假设我有一个这样的状态:{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
,这会最大限度地重复使用代码并最大限度地减少重复实现。
记忆
记忆化意味着当你用相同的参数多次调用一个函数时,该函数只会执行一次。纯函数 return 无论调用多少次或何时调用,给定相同参数的结果相同。
这意味着当您使用相同的参数再次调用它时不需要执行该函数,因为您已经知道结果。
Memoization 可用于不调用昂贵的函数(如过滤大型数组)。在 React 中,记忆很重要,因为如果 props 发生变化,纯组件将重新渲染:
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
没有改变过滤器函数每次都会 return 一个新数组。
工作原理
下面是对 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
);