【问题标题】:Advantage of Reselect over container componentReselect 相对于容器组件的优势
【发布时间】:2018-10-22 02:40:02
【问题描述】:

https://redux.js.org/recipes/computing-derived-data 描述了当组件依赖于作为计算值的属性时,如何使用 reselect createSelector() 来避免不必要的更新。

一种替代方法似乎是将必要的计算转移到一个(希望是)轻量级容器组件中,该组件连接到存储区。在这种情况下,mapStateToProps() 将返回对存储的引用,并且 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) 任何讨论上述方法的示例。

【问题讨论】:

    标签: reactjs redux components containers reselect


    【解决方案1】:

    如果您需要在多个容器中使用getVisibleTodos 怎么办?

    选择器将您的容器与商店分离。当存储形状发生变化时,您只需更新选择器即可使容器正常工作。

    For this reason, some would advocate placing selectors alongside the reducers.

    选择器在测试期间也很有用,允许您根据域逻辑而不是存储逻辑进行断言。这使得测试不那么脆弱。

    将选择器和操作视为公共商店 API 的两半,将其他所有内容视为易于更改的实现细节,这很有用。

    【讨论】:

    • 我同意关于测试和解耦的观点。关于可重用选择器,我认为this example 显示了事情如何变得有点失控(makeGetVisibleTodos 和 makeMapStateToProps)。容器组件非常简单。无论如何,这是一个自以为是的讨论,我相信随着我对这些库的更多经验,我会更清楚地了解这些优势。感谢您回答我的第一个溢出问题!
    【解决方案2】:

    此外,对于许多简单的情况(例如您的过滤示例),您可能希望选择一个更简陋的记忆功能,而不是为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 之间的分离较少

    我个人倾向于同时保留 createSelectormemoize 函数,并根据具体情况在它们之间进行选择。

    【讨论】: