在Redux中一次添加多个连接对象

时间:2017-06-28 01:48:03

标签: javascript redux

假设您有两个要存储在Redux中的对象AB,这些对象按照redux docs进行非规范化,如下所示:

state = {
  a: { byId: { id: { obj } }, allIds: [] },
  b: { byId: { id: { obj } }, allIds: [] }
};

您有一项操作,CREATE_A会向商店添加新的A但是,对于创建的每个A,它本身也需要B 。假设AB位于单独的reducer切片(即combineReducers)中,并且不能合并为一个。

很容易让B的reducer对CREATE_A事件做出反应并创建一个新的B,但如果B对象需要A该怎么办?刚刚创建的ID?

即使有一个join table邀请加入BA,仍然存在“知道首先创建的A”的问题。我提出的解决方案是存储最后创建的A,如下所示:

a: { lastCreated: {}, byId: etc, allIds: etc }

然后将整个状态树传递给B的reducer或连接表reducer,以便它可以访问state.a.lastCreated。但是,如果只有一个键,以便以后的减速器知道发生了什么(减速器需要某种排序的想法似乎也是错误的),这感觉不对。

我认为您也可以使用新的CREATE_B ID来发送A,但这必须在异步操作中完成(因为您无法从reducer发送),这也感觉不对。

在程序世界中,这将是微不足道的:

a = createA();
createB(a);

但即使有两次发送,我也不确定它会如何起作用:

dispatch( createA() )
dispatch( createB(???) )

处理“A-inherently-means-B-as-well”案例的最佳方法是什么?

编辑:让我尝试使用一些更具体的例子。

假设你有squarepoint。自然地创建square 意味着创建4个point。这些点与正方形相连,因为它们形成正方形,但它们也不属于到正方形,因为它们可以是它们自己的独立对象:

square with points

所以,ADD_SQUARE需要添加一个正方形,并添加4个点,然后将两个加在一起,如果不直接在父“状态”中编写reducer,我不知道如何做到这一点像这样(我想要做到这一点,它真的很乱,想象不得不重复3-8个边多边形):

function reducer(state, action) {
    switch(state) {
    case ADD_SQUARE:
        const points = create4Points();
        const square = createSquare();
        return {
            ...state,
            squares: {
                ...state.squares,
                byId: {
                    ...state.squares.byId
                    [square.id]: square
                }
            },
            points: {
                ...state.points,
                byId: {
                    ...state.points.byId,
                    [point[0].id]: point[0],
                    [point[1].id]: point[1],
                    [point[2].id]: point[2],
                    [point[3].id]: point[3]
                }
            },
            pointsSquares: {
                ...state.pointsSquares,
                byId: {
                    [square.id]: {
                        square: square.id,
                        points: [point1.id, point2.id, point3.id, point4.id]
                    }
                }
            }
        };
    }
}

2 个答案:

答案 0 :(得分:2)

你可以在A和B缩减器中定义相同的动作..就像这样 -

function reducerA(state, action) {
  switch(action.type) {
    case A_CREATE:
         do A stuff
  }
}


function reducerB(state, action) {
  switch(action.type) {
    case A_CREATE:
       do B stuff
  }
}

然后当你发出动作时,它会影响两个减速器。

function createA({id, stuff, etc}) {
  return {
    type: "A_CREATE",
    payload: {id, stuff, etc}
  }
}

然后你可以将id绑定到你需要创建的任何内容......从而将它们“连接”在一起。

编辑:

你可以使用redux thunk或者其他一些中间件,比如redux saga和promises来发送多个动作。

 `
  function handleACreation(payload) {
   dispatch(
      createA(payload)
       .then(result => dispatch(updateB(result)))
   )
  }
 `
显然,确切的代码不起作用 - 但总的想法仍然是:]希望这有帮助!

答案 1 :(得分:0)

就我而言,我通过在动作创建者中而不是在A的缩减器中创建A的ID来解决此问题。例如,

function createSquare () {
    return {
        type: CREATE_SQUARE,
        id: newUuid()
    };
}

function squareReducer ( state, action ) {
    switch ( action.type ) {
    case CREATE_SQUARE:
        return { id: action.id };
    }
}

function pointReducer ( state, action ) {
    switch ( action.type ) {
    case CREATE_SQUARE:
        return [
            { id: newUuid(), square: action.id }
            { id: newUuid(), square: action.id } //etc
        ];
    }
}

我仍然愿意接受其他解决方案。