Wolk9
Wolk9

Reputation: 69

How to 'extract' normalized data from redux store

In an earlier question I struggled with normalizing data with normalizr for storing into my Redux store.

This is the outcome: https://stackoverflow.com/a/70519781/16303828

const assistant = new schema.Entity("assistants");
const dentist = new schema.Entity("dentists");
const client = new schema.Entity("clients");
const userSchema = {
  assistants: [assistant],
  dentists: [dentist],
  clients: [client]
};
const normalizedUsers = normalize(users, userSchema);

the outcome of a console.log(normalisedUsers) is now:

{entities: {…}, result: {…}}
entities:
assistants: {201: {…}, 202: {…}}
clients: {1: {…}, 2: {…}}
dentists: {101: {…}, 102: {…}}
[[Prototype]]: Object
result:
assistants: (2) [201, 202]
clients: (2) [1, 2]
dentists: (2) [101, 102]
[[Prototype]]: Object
[[Prototype]]: Object

Now the question is: how do I refactor the Components in React to get that data displayed. Or am I still in error on how I normalized my data, and should I alter something there?

Upvotes: 0

Views: 360

Answers (1)

Summer
Summer

Reputation: 1301

You haven't actually shared any React components, so I'm just going to guess what you're trying to do. You want a <Assistant /> component to display each assistant, right? And same thing for clients and dentists.

Here's how I would do it, assuming the normalised data is in the redux store by now (note, requires lodash):

import { useSelector, shallowEqual } from 'react-redux'
import { keys, isEmpty } from 'lodash'
//       ^ equivalent to Object.keys() but with safety checks

export function AssistantsList() {
  const assistants = useSelector((state: RootState) => keys(state.assistants), shallowEqual)

  if (isEmpty(assistants)) return null
  return (
    <div>
      {assistants.map(id => (
        <Assistant key={id} id={Number(id)} />
      ))}
    </div>
  )
}

// typescript stuff: ignore if not using typescript
interface AssistantProps {
  id: number;
}

function Assistant({ id }: AssistantProps) {
  const { first_name, last_name, phone, email } = useSelector(
    (state: RootState) => state.assistants[id],
    shallowEqual
  )

  return (
    <div>
      <b>Assistant #{id}</b>
      <div>
        {first_name} {last_name}
      </div>
      <a href={`tel:${phone}`}>{phone}</a>
      <a href={`mailto:${email}`}>{email}</a>
    </div>
  )
}

// typescript stuff
type AssistantState = {
  id: number;
  first_name: string;
  last_name: string;
  phone: string;
  email: string;
}

// in a real app would be ReturnType<typeof store.getState>
// (where `store` is the redux store)
type RootState = {
  assistants: {
    [id: number]: AssistantState
  }
}

Upvotes: 1

Related Questions