“selector”是一个简单的Redux库,灵感来源于
NuclearJS
.html
//这个例子没必要太在乎,后面会有详细的介绍
import { createSelector } from 'reselect'
const shopItemsSelector = state => state.shop.items
const taxPercentSelector = state => state.shop.taxPercent
const subtotalSelector = createSelector(
shopItemsSelector,
items => items.reduce((acc, item) => acc + item.value, 0)
)
const taxSelector = createSelector(
subtotalSelector,
taxPercentSelector,
(subtotal, taxPercent) => subtotal * (taxPercent / 100)
)
export const totalSelector = createSelector(
subtotalSelector,
taxSelector,
(subtotal, tax) => ({ total: subtotal + tax })
)
let exampleState = {
shop: {
taxPercent: 8,
items: [
{ name: 'apple', value: 1.20 },
{ name: 'orange', value: 0.95 },
]
}
}
console.log(subtotalSelector(exampleState)) // 2.15
console.log(taxSelector(exampleState)) // 0.172
console.log(totalSelector(exampleState)) // { total: 2.322 }
复制代码
Installationreact
实例git
APIgithub
FAQtypescript
Licensejson
npm install reselect
redux
实例是基于 Redux Todos List example.设计模式
containers/VisibleTodoList.js
api
import { connect } from 'react-redux'
import { toggleTodo } from '../actions'
import TodoList from '../components/TodoList'
//下面这段代码是根据过滤器的state来改变日程state的函数
const getVisibleTodos = (todos, filter) => {
switch (filter) {
case 'SHOW_ALL':
return todos
case 'SHOW_COMPLETED':
return todos.filter(t => t.completed)
case 'SHOW_ACTIVE':
return todos.filter(t => !t.completed)
}
}
const mapStateToProps = (state) => {
return {
//todos是根据过滤函数返回的state,传入两个实参
todos: getVisibleTodos(state.todos, state.visibilityFilter)
}
}
//mapDispatchToProps来传递dispatch的方法
const mapDispatchToProps = (dispatch) => {
return {
onTodoClick: (id) => {
dispatch(toggleTodo(id))
}
}
}
//使用Redux的connect函数注入state,到TodoList组件
const VisibleTodoList = connect(
mapStateToProps,
mapDispatchToProps
)(TodoList)
export default VisibleTodoList
复制代码
在上面的例子中,mapStateToProps
调用getVisibleTodos
去计算todos
.这个函数设计的是至关好的,可是有个缺点:todos
在每一次组件更新的时候都会从新计算.若是state树的结构比较大,或者计算比较昂贵,每一次组件更新的时候都进行计算的话,将会致使性能问题.Reselect
可以帮助redux避免没必要要的计算过程.
咱们可使用记忆缓存selector代替getVisibleTodos
,若是state.todos
和state.visibilityFilter
发生变化,他会从新计算state
,可是只发生在其余部分的state变化,就不会从新计算.
Reslect提供一个函数createSelector
来建立一个记忆selectors.createSelector
接受input-selectors
和一个变换函数做为参数.若是Redux的state发生改变形成input-selector
的值发生改变,selector会调用变换函数,依据input-selector
作参数,返回一个结果.若是input-selector
返回的结果和前面的同样,那么就会直接返回有关state,会省略变换函数的调用.
下面咱们定义一个记忆selectorgetVisibleTodos
替代非记忆的版本
selectors/index.js
import { createSelector } from 'reselect'
const getVisibilityFilter = (state) => state.visibilityFilter
const getTodos = (state) => state.todos
//下面的函数是通过包装的
export const getVisibleTodos = createSelector(
[ getVisibilityFilter, getTodos ],
(visibilityFilter, todos) => {
switch (visibilityFilter) {
case 'SHOW_ALL':
return todos
case 'SHOW_COMPLETED':
return todos.filter(t => t.completed)
case 'SHOW_ACTIVE':
return todos.filter(t => !t.completed)
}
}
)
复制代码
上面的的实例中,getVisibilityfilter
和getTodos
是input-selectors.这两个函数是普通的非记忆selector函数,由于他们没有变换他们select的数据.getVisibleTodos
另外一方面是一个记忆selector.他接收getVisibilityfilter
和getTodos
做为input-selectors,而且做为一个变换函数计算筛选的todo list.
一个记忆性selector自己也能够做为另外一个记忆性selector的input-selector.这里getVisibleTodos
能够做为input-selector做为关键字筛选的input-selector:
const getKeyword = (state) => state.keyword
const getVisibleTodosFilteredByKeyword = createSelector(
[ getVisibleTodos, getKeyword ],
(visibleTodos, keyword) => visibleTodos.filter(
todo => todo.text.indexOf(keyword) > -1
)
)
复制代码
若是你正在使用 React Redux, 你能够 直接在mapStateToProps()
中调用 selector:
containers/VisibleTodoList.js
import { connect } from 'react-redux'
import { toggleTodo } from '../actions'
import TodoList from '../components/TodoList'
import { getVisibleTodos } from '../selectors'
const mapStateToProps = (state) => {
return {
todos: getVisibleTodos(state)
}
}
const mapDispatchToProps = (dispatch) => {
return {
onTodoClick: (id) => {
dispatch(toggleTodo(id))
}
}
}
const VisibleTodoList = connect(
mapStateToProps,
mapDispatchToProps
)(TodoList)
export default VisibleTodoList
复制代码
这一部分咱们假设程序将会有一个扩展,咱们容许selector支持多重todo List.请注意若是要彻底实施这个扩展,reducers,components,actions等等都须要做出改变.这些内容和主题不是太相关,因此这里就省略掉了.
目前为止,咱们仅仅看到selectors接收store的state做为一个参数,其实一个selector叶能够接受props.
这里是一个App
组件,渲染出三个VisibleTodoList
组件,每个组件有ListId
属性.
components/App.js
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>
)
复制代码
每个VisibleTodoList
container应该根据各自的listId
属性获取state的不一样部分.因此咱们修改一下getVisibilityFilter
和getTodos
,便于接受一个属性参数
selectors/todoSelectors.js
import { createSelector } from 'reselect'
const getVisibilityFilter = (state, props) =>
state.todoLists[props.listId].visibilityFilter
const getTodos = (state, props) =>
state.todoLists[props.listId].todos //这里是为二维数组了
const getVisibleTodos = createSelector(
[ getVisibilityFilter, getTodos ],
(visibilityFilter, todos) => {
switch (visibilityFilter) {
case 'SHOW_COMPLETED':
return todos.filter(todo => todo.completed)
case 'SHOW_ACTIVE':
return todos.filter(todo => !todo.completed)
default:
return todos
}
}
)
export default getVisibleTodos
复制代码
props
能够从mapStateToProps
传递到getVisibleTodos
:
const mapStateToProps = (state, props) => {
return {
todos: getVisibleTodos(state, props)
}
}
复制代码
如今getVisibleTodos
能够获取props
,每一部分彷佛都工做的不错.
**可是还有个问题! 当getVisibleTodos
selector和VisibleTodoList
container的多个实例一块儿工做的时候,记忆功能就不能正常运行:
containers/VisibleTodoList.js
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
//⚠️下面的selector不能正确的记忆
todos: getVisibleTodos(state, props)
}
}
const mapDispatchToProps = (dispatch) => {
return {
onTodoClick: (id) => {
dispatch(toggleTodo(id))
}
}
}
const VisibleTodoList = connect(
mapStateToProps,
mapDispatchToProps
)(TodoList)
export default VisibleTodoList
复制代码
使用createSelector
建立的selector时候,若是他的参数集合和上一次的参数机会是同样的,仅仅返回缓存的值.若是咱们交替渲染<VisibleTodoList listId="1" />
和<VisibleTodoList listId="2" />
时,共享的selector将会交替接受{listId:1}
和{listId:2}
做为他的props的参数.这将会致使每一次调用的时候的参数都不一样,所以selector每次都会从新来计算而不是返回缓存的值.下一部分咱们将会介绍怎么解决这个问题.
这一部分的实例须要React Redux v4.3.0或者更高版本的支持.
在多个VisibleTodoList
组件中共享selector,同时还要保持记忆性,每个组件的实例须要他们本身的selector私有拷贝.
如今让咱们建立一个函数makeGetVisibleTodos
,这个函数每次调用的时候返回一个新的getVisibleTodos
的拷贝:
selectors/todoSelectors.js
import { createSelector } from 'reselect'
const getVisibilityFilter = (state, props) =>
state.todoLists[props.listId].visibilityFilter
const getTodos = (state, props) =>
state.todoLists[props.listId].todos
const makeGetVisibleTodos = () => {
return createSelector(
[ getVisibilityFilter, getTodos ],
(visibilityFilter, todos) => {
switch (visibilityFilter) {
case 'SHOW_COMPLETED':
return todos.filter(todo => todo.completed)
case 'SHOW_ACTIVE':
return todos.filter(todo => !todo.completed)
default:
return todos
}
}
)
}
export default makeGetVisibleTodos
复制代码
咱们也须要设置给每个组件的实例他们各自获取私有的selector方法.mapStateToProps
的connect
函数能够帮助完成这个功能.
若是mapStateToProps
提供给connect
的不是一个对形象,而是一个函数,每一个container
中就会建立独立的mapStateToProps
实例.
在下面的实例中,mapStateProps
建立一个新的getVisibleTodos
selector,他返回一个mapStateToProps
函数,这个函数可以接入新的selector.
const makeMapStateToProps = () => {
const getVisibleTodos = makeGetVisibleTodos()
const mapStateToProps = (state, props) => {
return {
todos: getVisibleTodos(state, props)
}
}
return mapStateToProps
}
复制代码
若是咱们把makeMapStateToprops
传递到connect
,每个visibleTodoList
container将会得到各自的含有私有getVisibleTodos
selector的mapStateToProps
函数.这样一来记忆就正常了,无论VisibleTodoList
containers的渲染顺序怎么样.
containers/VisibleTodoList.js
import { connect } from 'react-redux'
import { toggleTodo } from '../actions'
import TodoList from '../components/TodoList'
import { makeGetVisibleTodos } from '../selectors'
const makeMapStateToProps = () => {
const getVisibleTodos = makeGetVisibleTodos()
const mapStateToProps = (state, props) => {
return {
todos: getVisibleTodos(state, props)
}
}
return mapStateToProps
}
const mapDispatchToProps = (dispatch) => {
return {
onTodoClick: (id) => {
dispatch(toggleTodo(id))
}
}
}
const VisibleTodoList = connect(
makeMapStateToProps,
mapDispatchToProps
)(TodoList)
export default VisibleTodoList
复制代码
接受一个或者多个selectors,或者一个selectors数组,计算他们的值而且做为参数传递给resultFunc
.
createSelector
经过判断input-selector以前调用和以后调用的返回值的全等于(===,这个地方英文文献叫reference equality,引用等于,这个单词是本质,中文没有翻译出来).通过createSelector
建立的selector应该是immutable(不变的).
通过createSelector
建立的Selectors有一个缓存,大小是1.这意味着当一个input-selector变化的时候,他们老是会从新计算state,由于Selector仅仅存储每个input-selector前一个值.
const mySelector = createSelector(
state => state.values.value1,
state => state.values.value2,
(value1, value2) => value1 + value2
)
// You can also pass an array of selectors
//能够出传递一个selector数组
const totalSelector = createSelector(
[
state => state.values.value1,
state => state.values.value2
],
(value1, value2) => value1 + value2
)
复制代码
在selector内部获取一个组件的props很是有用.当一个selector经过connect
函数链接到一个组件上,组件的属性做为第二个参数传递给selector:
const abSelector = (state, props) => state.a * props.b
// props only (ignoring state argument)
const cSelector = (_, props) => props.c
// state only (props argument omitted as not required)
const dSelector = state => state.d
const totalSelector = createSelector(
abSelector,
cSelector,
dSelector,
(ab, c, d) => ({
total: ab + c + d
})
)
复制代码
defaultMemoize
能记住经过func传递的参数.这是createSelector
使用的记忆函数.
defaultMemoize
经过调用equalityCheck
函数来决定一个参数是否已经发生改变.由于defaultMemoize
设计出来就是和immutable数据一块儿使用,默认的equalityCheck
使用引用全等于来判断变化:
function defaultEqualityCheck(currentVal, previousVal) {
return currentVal === previousVal
}
复制代码
defaultMemoize
和createSelectorCreator
去配置equalityCheck
函数.
createSelectorCreator
用来配置定制版本的createSelector
.
memoize
参数是一个有记忆功能的函数,来代替defaultMemoize
. …memoizeOption
展开的参数是0或者更多的配置选项,这些参数传递给memoizeFunc
.selectorsresultFunc
做为第一个参数传递给memoize
,memoizeOptions
做为第二个参数:
const customSelectorCreator = createSelectorCreator(
customMemoize, // function to be used to memoize resultFunc,记忆resultFunc
option1, // option1 will be passed as second argument to customMemoize 第二个惨呼
option2, // option2 will be passed as third argument to customMemoize 第三个参数
option3 // option3 will be passed as fourth argument to customMemoize 第四个参数
)
const customSelector = customSelectorCreator(
input1,
input2,
resultFunc // resultFunc will be passed as first argument to customMemoize 做为第一个参数传递给customMomize
)
复制代码
在customSelecotr
内部滴啊用memoize的函数的代码以下:
customMemoize(resultFunc, option1, option2, option3)
复制代码
下面是几个可能会用到的createSelectorCreator
的实例:
为defaultMemoize
配置equalityCheck
import { createSelectorCreator, defaultMemoize } from 'reselect'
import isEqual from 'lodash.isEqual'
// create a "selector creator" that uses lodash.isEqual instead of ===
const createDeepEqualSelector = createSelectorCreator(
defaultMemoize,
isEqual
)
// use the new "selector creator" to create a selector
const mySelector = createDeepEqualSelector(
state => state.values.filter(val => val < 5),
values => values.reduce((acc, val) => acc + val, 0)
)
复制代码
使用loadsh的memoize函数来缓存未绑定的缓存.
import { createSelectorCreator } from 'reselect'
import memoize from 'lodash.memoize'
let called = 0
const hashFn = (...args) => args.reduce(
(acc, val) => acc + '-' + JSON.stringify(val),
''
)
const customSelectorCreator = createSelectorCreator(memoize, hashFn)
const selector = customSelectorCreator(
state => state.a,
state => state.b,
(a, b) => {
called++
return a + b
}
)
复制代码
若是在普通的模式下使用createStructuredSelector
函数能够提高便利性.传递到connect
的selector装饰者(这是js设计模式的概念,能够参考相关的书籍)接受他的input-selectors,而且在一个对象内映射到一个键上.
const mySelectorA = state => state.a
const mySelectorB = state => state.b
// The result function in the following selector
// is simply building an object from the input selectors 由selectors构建的一个对象
const structuredSelector = createSelector(
mySelectorA,
mySelectorB,
mySelectorC,
(a, b, c) => ({
a,
b,
c
})
)
复制代码
createStructuredSelector
接受一个对象,这个对象的属性是input-selectors,函数返回一个结构性的selector.这个结构性的selector返回一个对象,对象的键和inputSelectors
的参数是相同的,可是使用selectors代替了其中的值.
const mySelectorA = state => state.a
const mySelectorB = state => state.b
const structuredSelector = createStructuredSelector({
x: mySelectorA,
y: mySelectorB
})
const result = structuredSelector({ a: 1, b: 2 }) // will produce { x: 1, y: 2 }
复制代码
结构性的selectors能够是嵌套式的:
const nestedSelector = createStructuredSelector({
subA: createStructuredSelector({
selectorA,
selectorB
}),
subB: createStructuredSelector({
selectorC,
selectorD
})
})
复制代码
A:检查一下你的记忆韩式是否是和你的state更新函数相兼容(例如:若是你正在使用Redux).例如:使用createSelector
建立的selector老是建立一个新的对象,原来期待的是更新一个已经存在的对象.createSelector
使用(===)检测输入是否改变,所以若是改变一个已经存在的对象没有触发selector从新计算的缘由是改变一个对象的时候没有触发相关的检测.提示:若是你正在使用Redux,改变一个state对象的错误可能有.
下面的实例定义了一个selector能够决定数组的第一个todo项目是否是已经被完成:
const isFirstTodoCompleteSelector = createSelector(
state => state.todos[0],
todo => todo && todo.completed
)
复制代码
下面的state更新函数和isFirstTodoCompleteSelector
将不会正常工做工做:
export default function todos(state = initialState, action) {
switch (action.type) {
case COMPLETE_ALL:
const areAllMarked = state.every(todo => todo.completed)
// BAD: mutating an existing object
return state.map(todo => {
todo.completed = !areAllMarked
return todo
})
default:
return state
}
}
复制代码
下面的state更新函数和isFirstTodoComplete
一块儿能够正常工做.
export default function todos(state = initialState, action) {
switch (action.type) {
case COMPLETE_ALL:
const areAllMarked = state.every(todo => todo.completed)
// GOOD: returning a new object each time with Object.assign
return state.map(todo => Object.assign({}, todo, {
completed: !areAllMarked
}))
default:
return state
}
}
复制代码
若是你没有使用Redux,可是有使用mutable数据的需求,你可使用createSelectorCreator
代替默认的记忆函数,而且使用不一样的等值检测函数.请参看这里 和 这里做为参考.
A: 检查一下你的记忆函数和你你的state更新函数是否是兼容(若是是使用Redux的时候,看看reducer).例如:使用每一次更新的时候,无论值是否是发生改变,createSelector
建立的selector老是会收到一个新的对象.createSelector
函数使用(===
)检测input的变化,由此可知若是每次都返回一个新对象,表示selector老是在每次更新的时候从新计算.
import { REMOVE_OLD } from '../constants/ActionTypes'
const initialState = [
{
text: 'Use Redux',
completed: false,
id: 0,
timestamp: Date.now()
}
]
export default function todos(state = initialState, action) {
switch (action.type) {
case REMOVE_OLD:
return state.filter(todo => {
return todo.timestamp + 30 * 24 * 60 * 60 * 1000 > Date.now()
})
default:
return state
}
}
复制代码
下面的selector在每一次REMOVE_OLD调用的时候,都会从新计算,由于Array.filter老是返回一个新对象.可是在大多数状况下,REMOVE_OLD action都不会改变todo列表,因此从新计算是没必要要的.
import { createSelector } from 'reselect'
const todosSelector = state => state.todos
export const visibleTodosSelector = createSelector(
todosSelector,
(todos) => {
...
}
)
复制代码
你能够经过state更新函数返回一个新对象来减小没必要要的重计算操做,这个对象执行深度等值检测,只有深度不相同的时候才返回新对象.
import { REMOVE_OLD } from '../constants/ActionTypes'
import isEqual from 'lodash.isEqual'
const initialState = [
{
text: 'Use Redux',
completed: false,
id: 0,
timestamp: Date.now()
}
]
export default function todos(state = initialState, action) {
switch (action.type) {
case REMOVE_OLD:
const updatedState = state.filter(todo => {
return todo.timestamp + 30 * 24 * 60 * 60 * 1000 > Date.now()
})
return isEqual(updatedState, state) ? state : updatedState
default:
return state
}
}
复制代码
替代的方法是,在selector中使用深度检测方法替代默认的equalityCheck
函数:
import { createSelectorCreator, defaultMemoize } from 'reselect'
import isEqual from 'lodash.isEqual'
const todosSelector = state => state.todos
// create a "selector creator" that uses lodash.isEqual instead of ===
const createDeepEqualSelector = createSelectorCreator(
defaultMemoize,
isEqual
)
// use the new "selector creator" to create a selector
const mySelector = createDeepEqualSelector(
todosSelector,
(todos) => {
...
}
)
复制代码
检查equalityCheck
函数的更替或者在state更新函数中作深度检测并不老是比重计算的花销小.若是每次重计算的花销老是比较小,可能的缘由是Reselect没有经过connect
函数传递mapStateProps
单纯对象的缘由.
A:能够.Reselect没有其余任何的依赖包,所以尽管他设计的和Redux比较搭配,可是独立使用也是能够的.目前的版本在传统的Flux APP下使用是比较成功的.
若是你使用
createSelector
建立的selectors,须要确保他的参数是immutable的.
看这里
A:Reselect没有支持建立接收参数的selectors,可是这里有一些实现相似函数功能的建议.
若是参数不是动态的,你可使用工厂函数:
const expensiveItemSelectorFactory = minValue => {
return createSelector(
shopItemsSelector,
items => items.filter(item => item.value > minValue)
)
}
const subtotalSelector = createSelector(
expensiveItemSelectorFactory(200),
items => items.reduce((acc, item) => acc + item.value, 0)
)
复制代码
总的达成共识看这里和超越 neclear-js是:若是一个selector须要动态的参数,那么参数应该是store中的state.若是你决定好了在应用中使用动态参数,像下面这样返回一个记忆函数是比较合适的:
import { createSelector } from 'reselect'
import memoize from 'lodash.memoize'
const expensiveSelector = createSelector(
state => state.items,
items => memoize(
minValue => items.filter(item => item.value > minValue)
)
)
const expensiveFilter = expensiveSelector(state)
const slightlyExpensive = expensiveFilter(100)
const veryExpensive = expensiveFilter(1000000)
复制代码
A: 我认为这个记忆韩式工做的还能够,可是若是你须要一个其余的韩式也是能够的. 能够看看这个例子
A:对于一个给定的input,一个selector老是产出相同的结果.基于这个缘由,作单元测试是很是简单的.
const selector = createSelector(
state => state.a,
state => state.b,
(a, b) => ({
c: a * 2,
d: b * 3
})
)
test("selector unit test", () => {
assert.deepEqual(selector({ a: 1, b: 2 }), { c: 2, d: 6 })
assert.deepEqual(selector({ a: 2, b: 3 }), { c: 4, d: 9 })
})
复制代码
在state更新函数调用的时候同时检测selector的记忆函数的功能也是很是有用的(例如 使用Redux的时候检查reducer).每个selector都有一个recomputations
方法返回从新计算的次数:
suite('selector', () => {
let state = { a: 1, b: 2 }
const reducer = (state, action) => (
{
a: action(state.a),
b: action(state.b)
}
)
const selector = createSelector(
state => state.a,
state => state.b,
(a, b) => ({
c: a * 2,
d: b * 3
})
)
const plusOne = x => x + 1
const id = x => x
test("selector unit test", () => {
state = reducer(state, plusOne)
assert.deepEqual(selector(state), { c: 4, d: 9 })
state = reducer(state, id)
assert.deepEqual(selector(state), { c: 4, d: 9 })
assert.equal(selector.recomputations(), 1)
state = reducer(state, plusOne)
assert.deepEqual(selector(state), { c: 6, d: 12 })
assert.equal(selector.recomputations(), 2)
})
})
复制代码
另外,selectors保留了最后一个函数调用结果的引用,这个引用做为.resultFunc
.若是你已经聚合了其余的selectors,这个函数引用能够帮助你测试每个selector,不须要从state中解耦测试.
例如若是你的selectors集合像下面这样:
selectors.js
export const firstSelector = createSelector( ... )
export const secondSelector = createSelector( ... )
export const thirdSelector = createSelector( ... )
export const myComposedSelector = createSelector(
firstSelector,
secondSelector,
thirdSelector,
(first, second, third) => first * second < third
)
复制代码
单元测试就像下面这样: test/selectors.js
// tests for the first three selectors...
test("firstSelector unit test", () => { ... })
test("secondSelector unit test", () => { ... })
test("thirdSelector unit test", () => { ... })
// We have already tested the previous
// three selector outputs so we can just call `.resultFunc`
// with the values we want to test directly:
test("myComposedSelector unit test", () => {
// here instead of calling selector()
// we just call selector.resultFunc()
assert(selector.resultFunc(1, 2, 3), true)
assert(selector.resultFunc(2, 2, 1), false)
})
复制代码
最后,每个selector有一个resetRecomputations
方法,重置recomputations方法为0,这个参数的意图是在面对复杂的selector的时候,须要不少独立的测试,你不须要管理复杂的手工计算,或者为每个测试建立”傻瓜”selector.
A:creatSelector
建立的Selectors应该能够和Immutable.js数据结构一块儿完美的工做. 若是你的selector正在重计算,而且你认为state没有发生变化,必定要确保知道哪个Immutable.js更新方法,这个方法只要一更新老是返回新对象.哪个方法只有集合实际发生变化的时候才返回新对象.
import Immutable from 'immutable'
let myMap = Immutable.Map({
a: 1,
b: 2,
c: 3
})
// set, merge and others only return a new obj when update changes collection
let newMap = myMap.set('a', 1)
assert.equal(myMap, newMap)
newMap = myMap.merge({ 'a', 1 })
assert.equal(myMap, newMap)
// map, reduce, filter and others always return a new obj
newMap = myMap.map(a => a * 1)
assert.notEqual(myMap, newMap)
复制代码
若是一个操做致使的selector更新老是返回一个新对象,可能会发生没必要要的重计算.看这里.这是一个关于pros的讨论,使用深全等于来检测例如immutable.js
来减小没必要要的重计算过程.
A: 使用createSelector
建立的Selector的缓存的大小只有1.这个设定使得多个组件的实例之间的参数不一样,跨组件共享selector变得不合适.这里也有几种办法来解决这个问题:
A: 是的!他们包含在package.json
里.能够很好的工做.
A:尝试一些这里助手函数,由MattSPalmer提供
由于Reselect不可能保证缓存你全部的需求,在作很是昂贵的计算的时候,这个方法比较有用.查看一下reselect-maps readme
reselect-map的优化措施仅仅使用在一些小的案例中,若是你不肯定是否是须要他,就不要使用它.
MIT