As our data becomes spread out across multiple reducers, it becomes important standardize how we access that data. Ultimately each “slice” of your redux store owns how that data is named or stored and it’s convenient to provide selector functions as a public interface to that data.
More about this technique can be found in the redux style guide: https://redux.js.org/style-guide/style-guide#use-selector-functions-to-read-from-store-state
It's also strongly recommended that you cache/memoize your selectors, especially as they get more complex. A common library to help with that pattern is reselect but we do not cover it in this lesson.
Jamund Ferguson: [0:00] As our data becomes spread out across multiple reducers, it becomes important to standardize how we access that data. Ultimately, each slice of our redux store owns how that data is named or stored, and it's convenient to provide selector functions as a public interface to that data.
[0:15] Inside of store/rates.js, create a new section at the bottom that says selectors. Beneath that we'll add two. Type export const getAmount = state ==> state.rates.amount. Beneath that, export const getCurrenyCode = state ==> state.rates.currenyCode. Let's do the same in store/user.js. Add a selectors section. Type export const getName = state ==> state.user.name.
[0:51] Let's put these new selectors to work. Back in RateTable.js, import {useSelector} from "react-redux". Below that type import { getName } from "../store/user". Within our function body we can type const name = useSelector, and then just pass in the selector, the getName function.
[1:10] With that, we now have access to name, and we will create at the bottom of our function a footer to our table using tfoot. We get a row and an individual data cell with the colSpan of 2. Inside that we'll say Prepared for {name}. You can see now the bottom of our table it says, in my case, Prepared for Jamund Ferguson.
[1:33] Let's put the selectors to use in other files as well. Like in ExchangeRate, instead of hand-coding the path to amount, we can say import { getAmount, getCurrencyCode } from "../store/rates". We can place those directly in the useSelector function.
[1:52] We refresh and yeah, it looks like everything's working fine. It pulls the amount very quickly, but now, if we want to rename how we store this data, if I want to call this fullName instead of name, I can simply update the selector in our slice here without having to go all around my application and update this path. It is just pretty convenient.
[2:15] It's also nice if I want to do something more with the selector. For example, if I wanted to return just the first name, I could do something like return user.fullName.split(" ") and return the first full word and my name, just Jamund. I can also lowercase it, toLowerCase(), or whatever additional thing I want to do in my selector. I can do it in one place rather than doing it all throughout my application.
[2:43] You can really think of selectors as the public API for accessing data in your store.