2

I'm adding normalizr to a redux application and I'm having a tricky time handling a unidirectional link in the data returned from an API.

Two separate API calls are made, the first one returns an author:

author = {
    ...authorFields,
}

The second one returns a list of books:

books = [
    {
        ...bookFields,
        authorId,
    },
    ...
]

Here is my normalizr schema:

const book = new schema.Entity('books')

const author = new schema.Entity('authors', {
  books: [ book ],
})

book.define('book', {
  author,
})

In our API response, we only have a link in the book, and not contained in the author. Just calling normalize() on the case won't give us the nice normalized state we want.

My target state is this (the normalized state that we would get if the author response from the API contained the books as nested entities):

{
    authors: {
        "101": {
            ...authorFields
            books: [
                "1001",
                "1002",
                etc...
            ]
        }
    books {
        "1001" : {
            "1001": {
                ...bookFields,
                author: "101",
            },
            "1002": {
                ...bookFields,
                author: "101",
            }
        }
    }
}

My approach was to handle things in the reducer.

Here's the books action creator (I'm using thunk):

function fetchBooksForAuthor(authorId) {
    return (dispatch, _, schema) => {
        return getBooksFromAPIByAuthor(authorId)
            .then(books => {
                const normalizedData = normalize(books, [ schema.book ])

                dispatch(addBooks({
                    authorId,
                    ...normalizedData
                }))
            })
    }
}

Here are the reducers:

function books(state = {}, action) {
      switch (action.type) {
          case ADD_BOOKS:
            return {
              ...state,
              ...action.payload.entities.books
            }
          ...
     }
 }

 function authors(state = {}, action) {
    switch (action.type) {
        case ADD_BOOKS:
            const authorId = action.payload.authorId
            const author = state[authorId]

            return {
              ...state,
              [authorId]: {
                ...author,
                ...action.payload.result
              }
            }
        ...
    }
}

Would this be the best way to handle this type of case? Is there any way of handling this type of case entirely inside normalizr? If not, does anyone have any suggestions as to the best way to handle this? Add another link in the API ^^?

  • You can check my thoughts about [How to deal with relational data in Redux?](https://stackoverflow.com/q/45373369/4312466). There I shared my experience and I'm sure you can take some insights. – Jordan Enev Jul 19 '18 at 14:08

0 Answers0