标准化 API 数据以用于 Redux
Normalize API data for use in Redux
我有以下来自 API 的数据:
const data = {
id: 1,
name: 'myboard',
columns: [
{
id: 1,
name: 'col1',
cards: [
{ id: 1, name: 'card1' },
{ id: 2, name: 'card2' }
]
},
{
id: 2,
name: 'col2',
cards: [
{ id: 3, name: 'card3' },
{ id: 4, name: 'card4' }
]
},
]
}
如您所见,基本上有 3 个嵌套级别。顶层包含一个 id
、name
和一个 columns
列表。每个 column
包含一个 id
、name
和一个 cards
的列表。每个 card
都有一个 id
和 name
.
我希望规范化数据以在 Redux 中使用 here. I am using normalizr 以按如下方式执行此操作:
const card = new schema.Entity('cards');
const column = new schema.Entity('columns', {
cards: [card]
});
const board = new schema.Entity('boards', {
columns: [column]
});
normalize(data, board)
结果如下:
{
"entities": {
"cards": {
"1": {
"id": 1,
"name": "card1"
},
"2": {
"id": 2,
"name": "card2"
},
"3": {
"id": 3,
"name": "card3"
},
"4": {
"id": 4,
"name": "card4"
}
},
"columns": {
"1": {
"id": 1,
"name": "col1",
"cards": [1, 2]
},
"2": {
"id": 2,
"name": "col2",
"cards": [3, 4]
}
},
"boards": {
"1": {
"id": 1,
"name": "myboard",
"columns": [1, 2]
}
}
},
"result": 1
}
我似乎无法弄清楚的是如何将每个部分(即:cards
、columns
、boards
)分成两部分,即byId
和 allIds
根据上面引用的 Redux 文章。
本质上这是为了让 React 应用程序中的排序、排序等更容易。我正在使用最新版本的 normalizr (3.2.4)。
Here is a CodeSandbox with an example 如何设置减速器来处理规范化状态。
基本上,您最终会为每个实体得到这样的结果:
// lambda or function - whatever your preference is
const cardsById = (state = {}, action) => {
// if, case, handler function - whatever your preference is
if (action.type === 'ADD_DATA') { // or whatever your initial data load type is
return { ...state, ...action.payload.cards }
}
return state
}
const allCards = (state = [], action) => {
if (action.type === 'ADD_DATA') { // or whatever your initial data load type is
return [...state, ...Object.keys(action.payload.cards)]
}
return state
}
const cards = combineReducers({
byId: cardsById,
allIds: allCards
})
然后将所有这些组合在一起:
export default combineReducers({
cards,
columns,
boards
})
此操作创建者如下:
const addData = ({ entities }) => ({
type: 'ADD_DATA',
payload: entities // note the rename - this is not required, just my preference
})
// I used a thunk, but theory is the the same for your async middleware of choice
export const getData = () => dispatch => dispatch(addData(normalize(data, board)))
希望这对您有所帮助。请记住,在添加或删除实体时,您需要为每个实体维护 byId
和 allIds
。
我有以下来自 API 的数据:
const data = {
id: 1,
name: 'myboard',
columns: [
{
id: 1,
name: 'col1',
cards: [
{ id: 1, name: 'card1' },
{ id: 2, name: 'card2' }
]
},
{
id: 2,
name: 'col2',
cards: [
{ id: 3, name: 'card3' },
{ id: 4, name: 'card4' }
]
},
]
}
如您所见,基本上有 3 个嵌套级别。顶层包含一个 id
、name
和一个 columns
列表。每个 column
包含一个 id
、name
和一个 cards
的列表。每个 card
都有一个 id
和 name
.
我希望规范化数据以在 Redux 中使用 here. I am using normalizr 以按如下方式执行此操作:
const card = new schema.Entity('cards');
const column = new schema.Entity('columns', {
cards: [card]
});
const board = new schema.Entity('boards', {
columns: [column]
});
normalize(data, board)
结果如下:
{
"entities": {
"cards": {
"1": {
"id": 1,
"name": "card1"
},
"2": {
"id": 2,
"name": "card2"
},
"3": {
"id": 3,
"name": "card3"
},
"4": {
"id": 4,
"name": "card4"
}
},
"columns": {
"1": {
"id": 1,
"name": "col1",
"cards": [1, 2]
},
"2": {
"id": 2,
"name": "col2",
"cards": [3, 4]
}
},
"boards": {
"1": {
"id": 1,
"name": "myboard",
"columns": [1, 2]
}
}
},
"result": 1
}
我似乎无法弄清楚的是如何将每个部分(即:cards
、columns
、boards
)分成两部分,即byId
和 allIds
根据上面引用的 Redux 文章。
本质上这是为了让 React 应用程序中的排序、排序等更容易。我正在使用最新版本的 normalizr (3.2.4)。
Here is a CodeSandbox with an example 如何设置减速器来处理规范化状态。
基本上,您最终会为每个实体得到这样的结果:
// lambda or function - whatever your preference is
const cardsById = (state = {}, action) => {
// if, case, handler function - whatever your preference is
if (action.type === 'ADD_DATA') { // or whatever your initial data load type is
return { ...state, ...action.payload.cards }
}
return state
}
const allCards = (state = [], action) => {
if (action.type === 'ADD_DATA') { // or whatever your initial data load type is
return [...state, ...Object.keys(action.payload.cards)]
}
return state
}
const cards = combineReducers({
byId: cardsById,
allIds: allCards
})
然后将所有这些组合在一起:
export default combineReducers({
cards,
columns,
boards
})
此操作创建者如下:
const addData = ({ entities }) => ({
type: 'ADD_DATA',
payload: entities // note the rename - this is not required, just my preference
})
// I used a thunk, but theory is the the same for your async middleware of choice
export const getData = () => dispatch => dispatch(addData(normalize(data, board)))
希望这对您有所帮助。请记住,在添加或删除实体时,您需要为每个实体维护 byId
和 allIds
。