【问题标题】:Connecting nested Redux smart components with reducers使用 reducer 连接嵌套的 Redux 智能组件
【发布时间】:2015-11-16 05:11:36
【问题描述】:

与 Redux 的 ToDo 示例类似,我的项目结构也类似 - 只是一个包含要显示的子组件数组的容器。商店将如下所示:

{
    workspace: {
        widgets: [1, 2, 3]
    }
    widgets: {
        1: {
            id: 1,
            title: 'First Widget',
            lastPrice: 123.324,
            lastUpdate: '2015-11-12'
        },
        2: {
            id: 2,
            title: 'Second Widget',
            lastPrice: 1.624,
            lastUpdate: '2015-11-12'
        },
        3: {
            id: 3,
            title: 'Third Widget',
            lastPrice: 4.345,
            lastUpdate: '2015-11-12'
        }
    }
}

每个小部件项本身就是一个复杂的组件——许多可能的操作、许多属性和许多子哑组件。因此,我将每个小部件都做成了一个连接的智能组件,并带有一个专用的 WidgetReducer 以将这些状态更改分开。

我希望 WidgetReducer 一次只关注一个小部件,因此它处理的状态将只是一个小部件节点,例如:

{   id: 3,
    title: 'Third Widget',
    lastPrice: 4.345,
    lastUpdate: '2015-11-12'
}

My Workspace 组件目前遍历所有 Widget,将 Widget ID 传递给每个 Widget 智能组件:

@connect(state => ({ workspace: state.workspace }))
export default class Workspace extends React.Component {
    render() {
        return (
            <div>
                {this.props.workspace.widgets.map(id =>
                    (<Widget key={id} widgetId={id} />)
                )}
            </div>
        );
    }
}

我的 Widget 组件是这样的:

@connect((state, ownProps) => ({ widget: state.widgets[ownProps.widgetId]}))
export default class Widget extends React.Component {
    componentWillMount() {
        this.props.dispatch(subscribeToUpdates(this.props.widgetId));
    }

    render() {
        return (
            <div>
                <header>{this.props.widget.title}</header>
                <div> /* Other widget stuff goes here */</div>
            </div>
        );
    }
}

如何连接每个 Widget 组件,使其仅接收其自己的 Widget 对象的状态更新,而连接的 Widget Reducer 只关注单个 Widget 对象,而不是它们的集合?

【问题讨论】:

  • 您能再详细说明一下吗? reducer 不接收状态,只接收动作。你的问题有点模棱两可......你可以调度一个动作,它的属性包含你需要的数据片段......不确定这是否是你想要的。
  • 我试图澄清...如果仍然不清楚,请告诉我!谢谢。
  • @Seneca 只是想指出,reducer 是一个纯函数,它接受一个状态和一个动作并吐出一个新状态。 github.com/rackt/redux#the-gist

标签: javascript reactjs redux


【解决方案1】:

首先看一下Reselect: https://github.com/rackt/reselect

如果我理解这个问题,这就是你要找的。 假设widget-id 2 的状态发生了变化,widget 1 和widget 3 并不关心widget-id 2 的状态是否改变。只有小部件 2 需要反映该更改。重新选择使您能够构建“记忆化”选择功能。这可能听起来像是一个花哨的词,但实际上它意味着只有选择选择器的输入值更改,它将计算下一个状态。

在小部件示例中,您将构建选择函数,仅当它所关注的状态切片发生变化时才重新计算状态。

可能的例子:

import { createSelector } from 'reselect'

const widgetByIdSelector = (state, props) => state.widgets[props.widgetId]
// this is the `input` function for you selector: as input we take the   
// specific slice of state a specific widgetId requests.
// the main idea is: only if the `input` of this function changes, it'll 'reselect' that state.

export const widgetSelector = createSelector(
   widgetByIdSelector,
    (widgetById) => { 
         return { widgetById } 
   }

@connect(widgetSelector)
export default class Widget extends Component { ... }

我不知道这段代码是否可行,我是在火车上写的,互联网连接不稳定,但这是主要的想法......

至于 reducer 和 action creators(你可能会做这样的事情):

export function createActionForSpecificWidgetById(widgetId, payload) {
    return {
       type: ACTIONS.HERE_COMES_YOUR_ACTION_TYPE,
       widgetId,
       payload
    }
}

function reducer(state = initialState, action) {
  switch(action.type) {
  case HERE_COMES_YOUR_ACTION_TYPE:
      //now you can modify the state of the specific widgetId because you have access to the id at action.widgetId
}

这就是你要找的吗?

【讨论】:

  • 这非常有用,是的,重新选择肯定会有所帮助。虽然它并没有完全回答问题的第二部分 - 传递给减速器和从减速器返回的状态,我想成为单个小部件对象,而不是我需要提取我的特定小部件的所有小部件的集合小部件按 ID。我开始认为这不可能?
  • 进一步考虑,这在技术上可能是可行的,但它会是一个小部件减速器集合的情况,然后其结果将组合成商店中的小部件集合(如 @987654322 所述@)。不漂亮,也没有必要。只是我对 Redux 工作原理的新手理解 :)
  • 所以你想要 combineReducers({widgets: combineReducers({widget1: widgetReducer1, widget2: widgetReducer2, widget2: widgetReducer3}}) ? 现在你的状态看起来像 {widget: {widget1: {}, widget2: {},小部件 3:{}}
猜你喜欢
  • 1970-01-01
  • 2018-02-15
  • 1970-01-01
  • 2019-04-26
  • 2017-05-21
  • 1970-01-01
  • 2019-11-16
  • 2017-09-03
  • 1970-01-01
相关资源
最近更新 更多