Reselect 相对于容器组件的优势
Advantage of Reselect over container component
https://redux.js.org/recipes/computing-derived-data 描述了如何使用 reselect createSelector() 来避免在组件依赖于作为计算值的属性时进行不必要的更新。
另一种方法似乎是将必要的计算转移到(希望)连接到商店的轻量级容器组件中。在这种情况下 mapStateToProps() 将 return 引用存储并且 connect() 不会触发容器组件的更新,除非商店中的相关值已更改:
import { connect } from 'react-redux'
import { toggleTodo } from '../actions'
import TodoList from '../components/TodoList'
const mapStateToProps = state => {
return {
visibilityFilter: state.visibilityFilter,
todos: state.todos,
}
}
const mapDispatchToProps = dispatch => {
return {
onTodoClick: id => {
dispatch(toggleTodo(id))
}
}
}
const connected = connect(
mapStateToProps,
mapDispatchToProps
)
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 VisibleTodoList = connected((props) => {
return <TodoList
todos={getVisibleTodos(props.todos, props.visibilityFilter)}
onTodoClick={props.onTodoClick}
/>
})
export default VisibleTodoList
是否有任何理由优先选择 reselect 而不是连接的容器组件?我找不到 (m) 任何讨论上述方法的例子。
如果需要在多个容器中使用getVisibleTodos
怎么办?
选择器将您的容器与商店分离。当商店形状发生变化时,您只需更新选择器即可使容器正常工作。
For this reason, some would advocate placing selectors alongside the reducers.
选择器在测试期间也很有用,允许您根据域逻辑而不是存储逻辑进行断言。这使测试不那么脆弱。
将选择器和操作视为 public 存储 API 的两半是很有用的,其他一切都是易于更改的实现细节。
此外,对于许多简单的情况(如您的过滤示例),您可能希望为 createSelector()
:
选择更简陋的记忆功能而不是更隆重的设置
const selectVisibleTodos = memoize(getVisibleTodos)
const mapStateToProps = state => ({
todos: selectVisibleTodos(state.todos, state.visibilityFilter),
})
对
const selectVisibleTodos = createSelector(
(state) => state.todos,
(state) => state.visibilityFilter,
getVisibleTodos
)
const mapStateToProps = state => ({
todos: selectVisibleTodos(state),
})
优点:
- 更简洁的代码
- 比
createSelector
更快(内部开销更少)
缺点:
mapSateToProps
和 redux 的形状 state
之间的分离较少
我个人倾向于同时保留 createSelector
和 memoize
功能,并根据具体情况在它们之间进行选择。
https://redux.js.org/recipes/computing-derived-data 描述了如何使用 reselect createSelector() 来避免在组件依赖于作为计算值的属性时进行不必要的更新。
另一种方法似乎是将必要的计算转移到(希望)连接到商店的轻量级容器组件中。在这种情况下 mapStateToProps() 将 return 引用存储并且 connect() 不会触发容器组件的更新,除非商店中的相关值已更改:
import { connect } from 'react-redux'
import { toggleTodo } from '../actions'
import TodoList from '../components/TodoList'
const mapStateToProps = state => {
return {
visibilityFilter: state.visibilityFilter,
todos: state.todos,
}
}
const mapDispatchToProps = dispatch => {
return {
onTodoClick: id => {
dispatch(toggleTodo(id))
}
}
}
const connected = connect(
mapStateToProps,
mapDispatchToProps
)
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 VisibleTodoList = connected((props) => {
return <TodoList
todos={getVisibleTodos(props.todos, props.visibilityFilter)}
onTodoClick={props.onTodoClick}
/>
})
export default VisibleTodoList
是否有任何理由优先选择 reselect 而不是连接的容器组件?我找不到 (m) 任何讨论上述方法的例子。
如果需要在多个容器中使用getVisibleTodos
怎么办?
选择器将您的容器与商店分离。当商店形状发生变化时,您只需更新选择器即可使容器正常工作。
For this reason, some would advocate placing selectors alongside the reducers.
选择器在测试期间也很有用,允许您根据域逻辑而不是存储逻辑进行断言。这使测试不那么脆弱。
将选择器和操作视为 public 存储 API 的两半是很有用的,其他一切都是易于更改的实现细节。
此外,对于许多简单的情况(如您的过滤示例),您可能希望为 createSelector()
:
const selectVisibleTodos = memoize(getVisibleTodos)
const mapStateToProps = state => ({
todos: selectVisibleTodos(state.todos, state.visibilityFilter),
})
对
const selectVisibleTodos = createSelector(
(state) => state.todos,
(state) => state.visibilityFilter,
getVisibleTodos
)
const mapStateToProps = state => ({
todos: selectVisibleTodos(state),
})
优点:
- 更简洁的代码
- 比
createSelector
更快(内部开销更少)
缺点:
mapSateToProps
和 redux 的形状state
之间的分离较少
我个人倾向于同时保留 createSelector
和 memoize
功能,并根据具体情况在它们之间进行选择。