Categories
Redux

Accessing the Store with React-Redux

With Redux, we can use it to store data in a central location in our JavaScript app. It can work alone and it’s also a popular state management solution for React apps when combined with React-Redux.

In this article, we’ll look at how to access the Redux store with React-Redux.

Accessing the Store

With React-Redux, we can access the store by defining a mapStateToProps function.

However, we can also access it in a customized way. Internally, React-Redux uses React’s Context API to make the Redux store accessible to deeply nested connected components.

Currently, React-Redux is normally handled by a single default context object instance generated by React.createContext() called ReactReduxContext .

Provider uses ReactReduxContext.Provider to put the Redux Store and the current state into context and connect uses ReactReduxContext.Consumer to read values and handle updates.

Providing Custom Context

We can provide a custom context to React-Redux via the context prop.

For example, we can pass in our own context in the following code:

import React from "re
import ReactDOM from "react-dom";
import { connect, Provider } from "react-redux";
import { createStore } from "redux";
function count(state = 0, action) {
  switch (action.type) {
    case "INCREMENT":
      return state + 1;
    case "DECREMENT":
      return state - 1;
    default:
      return state;
  }
}
const store = createStore(count);

function App({ increment, decrement, count }) {
  return (
    <div className="App">
      <button onClick={increment}>Increment</button>
      <button onClick={decrement}>Decrement</button>
      <p>{count}</p>
    </div>
  );
}
const mapStateToProps = state => {
  return { count: state };
};
const increment = () => ({ type: "INCREMENT" });
const decrement = () => ({ type: "DECREMENT" });
const customContext = React.createContext();

App = connect(
  mapStateToProps,
  { increment, decrement },
  null,
  { context: customContext }
)(App);

const rootElement = document.getElementById("root");
ReactDOM.render(
  <Provider store={store} context={customContext}>
    <App />
  </Provider>,
  rootElement
);

In the code above, we have the usual React-Redux code for connecting the store to the App component via connect .

However, we create a customContext via:

const customContext = React.createContext();

Then in the connect call, we have:

App = connect(
  mapStateToProps,
  { increment, decrement },
  null,
  { context: customContext }
)(App);

The 4th argument is { context: customContext } , which is where we set our custom context.

Also, we have:

<Provider store={store} context={customContext}>
  <App />
</Provider>

to set our context prop via context={customContext} .

Multiple Stores

We can also use multiple stores with React-Redux by nesting providers as follows:

import React from "react";
import ReactDOM from "react-dom";
import { connect, Provider } from "react-redux";
import { createStore, compose } from "redux";
function countA(state = 0, action) {
  switch (action.type) {
    case "INCREMENT":
      return state + 1;
    default:
      return state;
  }
}

function countB(state = 0, action) {
  switch (action.type) {
    case "DECREMENT":
      return state - 1;
    default:
      return state;
  }
}

const storeA = createStore(countA);
const storeB = createStore(countB);
function App({ increment, decrement, countA, countB }) {
  return (
    <div className="App">
      <button onClick={increment}>Increment</button>
      <button onClick={decrement}>Decrement</button>
      <p>{countA}</p>
      <p>{countB}</p>
    </div>
  );
}
const mapStateToPropsA = state => {
  return { countA: state };
};

const mapStateToPropsB = state => {
  return { countB: state };
};

const increment = () => ({ type: "INCREMENT" });
const decrement = () => ({ type: "DECREMENT" });
const contextA = React.createContext();
const contextB = React.createContext();

App = compose(
  connect(
    mapStateToPropsA,
    { increment },
    null,
    { context: contextA }
  ),
  connect(
    mapStateToPropsB,
    { decrement },
    null,
    { context: contextB }
  )
)(App);

const rootElement = document.getElementById("root");
ReactDOM.render(
  <Provider store={storeA} context={contextA}>
    <Provider store={storeB} context={contextB}>
      <App />
    </Provider>
  </Provider>,
  rootElement
);

In the code above, we defined 2 separate stores by writing:

const storeA = createStore(countA);
const storeB = createStore(countB);

where countA and countB are the reducers.

Then we nest our connect calls within the arguments of the compose function to combine the connects as follows:

App = compose(
  connect(
    mapStateToPropsA,
    { increment },
    null,
    { context: contextA }
  ),
  connect(
    mapStateToPropsB,
    { decrement },
    null,
    { context: contextB }
  )
)(App);

We defined mapStateToPropsA and mapStateToPropsB to map states from the 2 stores before this call.

Then in the last argument of each connect , we pass in an object with the context that we want to use to connect the store to App .

Then in the ReactDOM.render call, we pass in:

<Provider store={storeA} context={contextA}>
  <Provider store={storeB} context={contextB}>
    <App />
  </Provider>
</Provider>

to set the store and context we want to use for each provider. The context prop of each Provider have to match with connect .

Conclusion

We can access multiple stores by nesting multiple Providers and providing a store and context for each.

The context is defined by calling React.createContext() , which is part of the React Context API used to share data between components.

Then we can use the compose function to add combine multiple connect calls together. We pass into the 4th argument of connect in each call.

We can also use the same method to customize access to a single store, except that we don’t need to call compose .

Categories
Redux

Defining and Using React Redux mapDispatchToProps

With Redux, we can use it to store data in a central location in our JavaScript app. It can work alone and it’s also a popular state management solution for React apps when combined with React-Redux.

In this article, we’ll look at how to define and use the mapDispatchToProps function to map dispatch to props so we can call them in our React components.

Approaches for Dispatching

dispatch is a function of the Redux store. We call the store.dispatch method to dispatch an action to the tore.

It’s the only way to trigger a state change.

React components never access the store directly. We use the connect function to do it.

React Redux gives us 2 ways to let our components dispatch actions. We can either receive dispatch as a prop to dispatch actions itself, or we can use the connect function with a mapDispatchToProps function and pass as props to our component.

Default: dispatch as a Prop

For example, if we have the following code:

import React from "react";
import ReactDOM from "react-dom";
import { connect, Provider } from "react-redux";
import { createStore } from "redux";

function message(state = "", action) {
  switch (action.type) {
    case "SET_MESSAGE":
      return action.message;
    default:
      return state;
  }
}

const store = createStore(message);

const mapStateToProps = (state, ownProps) => {
  const { color } = ownProps;
  return { color, message: state };
};

function App({ dispatch, message }) {
  const onClick = () => {
    if (message === "bar") {
      dispatch({ type: "SET_MESSAGE", message: "foo" });
    } else {
      dispatch({ type: "SET_MESSAGE", message: "bar" });
    }
  };
  return (
    <div className="App">
      <button onClick={onClick}>Click Me</button>
      <p>{message}</p>
    </div>
  );
}

App = connect(mapStateToProps)(App);

const rootElement = document.getElementById("root");
ReactDOM.render(
  <Provider store={store}>
    <App />
  </Provider>,
  rootElement
);

Then when we click the button, we toggle between ‘foo’ and ‘bar’ being displayed because the connect higher-order component gives us the dispatch prop, which we can use to dispatch actions to our store.

Providing a mapDispatchToProps Parameter

The second way to use the mapDispatchToProps function to map the dispatch functions to our React component as props.

This is useful because we don’t have to call dispatch with all the arguments all the time.

It makes the dispatch implementation more declarative. With mapDispatchToProps , our component code doesn’t need to be aware of dispatch anymore.

mapStateToProps encapsulates the logic of talking to the Redux store so we don’t have to worry about it.

Two Forms of mapDispatchToProps

mapStateToProps can take the form of a function or an object. The function version allows for more customization since it as access to dispatch and ownProps as an option.

The object shorthand is shorter and easier to use. It’s better to use the object unless we have to customize dispatching in some way.

We’ll look at how to define mapDispatchToProps as a function.

Photo by Stephanie Studer on Unsplash

Defining mapDispatchToProps As A Function

We can define mapDispatchToProps as a function by defining a function that takes dispatch and optionally ownProps and calling dispatch with some action in the function.

We can use mapDispatchToProps as follows:

import React, { useEffect } from "react";
import ReactDOM from "react-dom";
import { connect, Provider } from "react-redux";
import { createStore } from "redux";

function messages(state = 0, action) {
  const words = ["foo", "bar", "baz"];
  switch (action.type) {
    case "GET_BY_INDEX":
      return words[action.index];
    default:
      return state;
  }
}

const store = createStore(messages);

function Message({ getByIndex, index, message }) {
  useEffect(() => {
    getByIndex(index);
  }, []);
  return (
    <div className="App">
      <p>{message}</p>
    </div>
  );
}

const mapStateToProps = (state, ownProps) => {
  return { message: state };
};

const mapDispatchToProps = (dispatch, ownProps) => {
  const { index } = ownProps;
  return {
    getByIndex: index => dispatch({ type: "GET_BY_INDEX", index })
  };
};

Message = connect(
  mapStateToProps,
  mapDispatchToProps
)(Message);

function App() {
  return (
    <div className="App">
      <Message index={0} />
    </div>
  );
}

const rootElement = document.getElementById("root");
ReactDOM.render(
  <Provider store={store}>
    <App />
  </Provider>,
  rootElement
);

In the code above, we have the store which lets us get messages from a list of words from the words array.

Then we defined mapDispatchToProps as follows:

const mapDispatchToProps = (dispatch, ownProps) => {
  const { index } = ownProps;
  return {
    getByIndex: index => dispatch({ type: "GET_BY_INDEX", index })
  };
};

In the code above, we have ownProps to access the index prop that we passed to the Message component.

Then we returned an object with the getByIndex method which takes an array index then we call dispatch with action type 'GET_BY_INDEX' and the index property with the index parameter as the value.

In the Message component, we get the getByIndex function that we returned from mapDispatchToProps , and index prop, and the message prop that we got from mapStateToProps and we used all of them.

We called getByIndex with the index prop value to get the string from the store with the given index in the useEffect callback. Then we displayed what we retrieved by adding:

<p>{message}</p>

Note that each field that returned in the object of mapStateTiProps will become a separate prop for our own component.

They’ll be merged with existing props.

Conclusion

To map code for dispatching actions to our React components, we can define the mapDispatchToProps function, which takes the dispatch function and ownProps as arguments. dispatch is what we call to dispatch actions to the store, and ownProps is an object with the props that we passed into components.

For dispatching simple actions, we can just use the connect function without defining a mapDispatchToProps function and we can call props.dispatch directly in the component to dispatch store actions since the connect higher-order component passed that to our component.

Categories
Redux

Defining and Using React Redux mapStateToProps Function

With Redux, we can use it to store data in a central location in our JavaScript app. It can work alone and it’s also a popular state management solution for React apps when combined with React-Redux.

In this article, we’ll look at how to use mapStateToProps to subscribe to the store’s state and them to a React component’s props.

mapStateToProps Definition

The React Redux’s mapStateToProps has 2 parameters. The first is the state and the second is an optional ownProps parameter.

It returns a plain object containing the data that the connected component needs.

It doesn’t matter if it’s a traditional function or an arrow function. Both kinds will give the same result.

The first argument, which is state , has the entire Redux store state. It’s the same value returned by store.getState() .

It’s usually called state . However, we can call it whatever we want.

The second parameter, ownProps , is an optional parameter that has the props of a component.

In the following example:

import React from "react";
import ReactDOM from "react-dom";
import { connect, Provider } from "react-redux";
import { createStore } from "redux";

function message(state = "hello", action) { switch (action.type) { default: return state; } }

const store = createStore(message);

function Message({ color, message }) { return <div style={{ color }}>{message}</div>; }

const mapStateToProps = (state, ownProps) => {
  const { color } = ownProps;
  return { color, message: state };
};

Message = connect(mapStateToProps)(Message);

function App() {
  return (
    <div className="App">
      <Message color="blue" />
    </div>
  );
}

const rootElement = document.getElementById("root"); ReactDOM.render( <Provider store={store}> <App /> </Provider>, rootElement );


`ownProps` would have the value of the `color` prop because that’s what we passed in.

In this case, that should be`blue` .

From the `mapStateToProps` function, we should also get the state from the store. In this case, we get the `'hello'` string returned from the `message` reducer function. So we should see ‘hello’ in the browser screen.

`mapStateToProps` function should be pure and synchronous. It only take the `state` and `ownProps` and return something that’s derived from it by running synchronous code.

This means no asynchronous HTTP calls, `setTimeout` , async functions, etc.

### Return Values Determine If Your Component Re-Renders

React-Redux internally implements the `shouldComponentUpdate` method. Therefore, the `Provider` will re-render when the data of our component has changed.

Data also includes entities retrieved from `mapStateToProps` .

The comparison is done by using the `===` comparison on each field of the returned object.

`mapStateToProps` runs when the store `state` changes. Or when `state` changes or `ownProps` is different if both `state` and `ownProps` are referenced.

The component re-renders when any field that’s returned by `mapStateToProps` is different.

If both `state` and `ownProps` are referenced in `mapStateToProps` , the component re-renders when any field of `stateProps` or `ownProps` are different.

### Only Return New Object References If Needed

Because `mapStateToProps` and re-rendering is done when we return new object or array references, we should only return new objects when we need them.

Therefore, we should avoid any code that returns new objects, like `array.map()` , `array.filter()` , etc.

If we need to run code that returns new object references, then they should be memoized so that they don’t trigger re-render even if their content is the same.

![](https://cdn-images-1.medium.com/max/800/0*MyfaaQ74D5h-plLE)Photo by [Pineapple Supply Co.](https://unsplash.com/@pineapple?utm_source=medium&utm_medium=referral) on [Unsplash](https://unsplash.com?utm_source=medium&utm_medium=referral)

### `mapStateToProps` Will Not Run if the Store State is the Same

Every time an action is dispatched, `store.getState()` is called to check if the previous state and the current state are the same.

If both states are identical by reference, then `mapStateToProps` won’t be run again since it assumes that the rest of the store haven’t changed.

`combineReducers` returns the old state object instead of the new one if there’re no changes in the store’s state.

### The Number of Declared Arguments Affects Behavior

If `ownProps` is omitted from the parameters, then `ownProps` won’t be retrieved. Therefore, we should only add `ownProps` to the parameter is we need it.

For example, if we have the following `mapStateToProps` function:

function mapStateToProps(state) { console.log(state) console.log(arguments[1]) }


The `arguments[1]` is `undefined` since we didn’t include the `ownProps` parameter.

### Conclusion

We can define `mapStateToProps` and use it to get the latest state from our Redux Store to our React app via the `connect` function.

It has 2 parameters, which are `state` for the store’s state and `ownProps` for the props that we pass into the component ourselves.

The `connect` function lets us pass in `mapStateToProps` as the first argument and returns a function where we can pass in our component into the it and returns a new component that subscribes to the store’s state and gets it as props.
Categories
Redux

Using the Redux Thunk to Dispatch Async Actions with React

With Redux, we can use it to store data in a central location in our JavaScript app. It can work alone and it’s also a popular state management solution for React apps when combined with React-Redux.

In this article, we’ll look at how to use React Redux and Redux Thunk to dispatch async actions in a React app.

Installation

Redux Thunk is available with the redux-thunk package. To install it, we run:

npm install redux-thunk

Usage

We can use it by using the applyMiddleware function to apply the thunk middleware from redux-thunk .

For example, we can use it as follows:

import React, { useEffect } from "react";
import ReactDOM from "react-dom";
import { Provider, useSelector, useDispatch } from "react-redux";
import { createStore, applyMiddleware } from "redux";
import thunk from "redux-thunk";

function joke(state = {}, action) {
  switch (action.type) {
    case "SET_JOKE":
      return { ...action.joke };
    default:
      return state;
  }
}

const store = createStore(joke, applyMiddleware(thunk));

const fetchJoke = () => {
  return async dispatch => {
    const response = await fetch("https://api.icndb.com/jokes/random/");
    const joke = await response.json();
    console.log(joke);
    dispatch({ type: "SET_JOKE", joke });
  };
};

function App() {
  const joke = useSelector(state => state.value && state.value.joke);
  const dispatch = useDispatch();

  useEffect(() => {
    dispatch(fetchJoke());
  }, []);
  return <div className="App">{joke}</div>;
}

const rootElement = document.getElementById("root");
ReactDOM.render(
  <Provider store={store}>
    <App />
  </Provider>,
  rootElement
);

In the code above, we have the fetchJoke function to dispatch an action into our store to get the joke and put the value in the store.

To dispatch async actions into our store, we have to apply the thunk middleware by writing:

const store = createStore(joke, applyMiddleware(thunk));

to apply the middleware.

Then in App , we call dispatch with the function returned from the fetchJoke passed inside. fetchJoke is an async action, which is also known as a thunk.

This will let us set the value from the API to the store properly.

Composing Actions

We can call another action within an action. Therefore, we can compose them by calling another action that we defined as follows:

import React, { useEffect } from "react";
import ReactDOM from "react-dom";
import { Provider, useSelector, useDispatch } from "react-redux";
import { createStore, applyMiddleware, combineReducers } from "redux";
import thunk from "redux-thunk";

function joke(state = {}, action) {
  switch (action.type) {
    case "SET_JOKE":
      return { ...action.joke };
    default:
      return state;
  }
}

function jokeById(state = {}, action) {
  switch (action.type) {
    case "SET_JOKE_BY_ID":
      return { ...action.joke };
    default:
      return state;
  }
}

const reducers = combineReducers({
  joke,
  jokeById
});
const store = createStore(reducers, applyMiddleware(thunk));

const fetchJokeById = id => {
  return async dispatch => {
    const response = await fetch(`[https://api.icndb.com/jokes/${id](https://api.icndb.com/jokes/$%7Bid)}
    `);
    const joke = await response.json();
    dispatch({ type: "SET_JOKE_BY_ID", joke });
  };
};

const fetchJoke = () => {
  return async dispatch => {
    const response = await fetch("https://api.icndb.com/jokes/random/");
    const joke = await response.json();
    dispatch({ type: "SET_JOKE", joke });
    dispatch(fetchJokeById(1));
  };
};

function App() {
  const joke = useSelector(state => state.joke.value && state.joke.value.joke);
  const jokeById = useSelector(
    state => state.jokeById.value && state.jokeById.value.joke
  );
  const dispatch = useDispatch();

  useEffect(() => {
    dispatch(fetchJoke());
  }, []);
  return (
    <div className="App">
      <p>{joke}</p>
      <p>{jokeById}</p>
    </div>
  );
}

const rootElement = document.getElementById("root");
ReactDOM.render(
  <Provider store={store}>
    <App />
  </Provider>,
  rootElement
);

In the code above, we have 2 reducers.

In App, we called fetchJoke by dispatching the function returned by fetchJoke to the store in the useEffect callback. In fetchJoke , we ran:

dispatch({ type: "SET_JOKE", joke });

to set the joke in the joke reducer and then also called:

dispatch(fetchJokeById(1));

which calls the action function returned by fetchJokeById . This populates the joke in the jokeById store.

Photo by Lauren Fleischmann on Unsplash

Injecting a Custom Argument

Since Redux Thunk 2.1.0, we can use the withExtraArgument function to inject extra arguments to the function that we return in the thunk.

For example, we can use that method as follows:

import React, { useEffect } from "react";
import ReactDOM from "react-dom";
import { Provider, useSelector, useDispatch } from "react-redux";
import { createStore, applyMiddleware } from "redux";
import thunk from "redux-thunk";
function joke(state = {}, action) {
  switch (action.type) {
    case "SET_JOKE":
      return { ...action.joke };
    default:
      return state;
  }
}

const api = "https://api.icndb.com/jokes/random/";
const store = createStore(joke, applyMiddleware(thunk.withExtraArgument(api)));
const fetchJoke = () => {
  return async (dispatch, getState, api) => {
    const response = await fetch(api);
    const joke = await response.json();
    console.log(joke);
    dispatch({ type: "SET_JOKE", joke });
  };
};

function App() {
  const joke = useSelector(state => state.value && state.value.joke);
  const dispatch = useDispatch();
  useEffect(() => {
    dispatch(fetchJoke());
  }, []);
  return <div className="App">{joke}</div>;
}

const rootElement = document.getElementById("root");
ReactDOM.render(
  <Provider store={store}>
    <App />
  </Provider>,
  rootElement
);

In the code above, we create the store by writing:

const store = createStore(joke, applyMiddleware(thunk.withExtraArgument(api)));

Then we have the following fetchJoke thunk:

const fetchJoke = () => {
  return async (dispatch, getState, api) => {
    const response = await fetch(api);
    const joke = await response.json();
    console.log(joke);
    dispatch({ type: "SET_JOKE", joke });
  };
};

which returns a function with 3 parameters. The third parameter is the argument that we passed in, which is api .

Conclusion

Using Redux Thunk, we can pass in any function that calls dispatch into the dispatch function to manipulate our Redux store state.

We apply the thunk middleware, then we can dispatch thunks.

This means that we can call dispatch with other thunks within a thunk, so we can compose them easily.

Since Redux Thunk 2.1.0, we can use the withExtraArgument function to add an extra argument to the action that we return the function that we want to use with dispatch.

Categories
Redux

Using the React-Redux Hooks API to Manipulate Store State

With Redux, we can use it to store data in a central location in our JavaScript app. It can work alone and it’s also a popular state management solution for React apps when combined with React-Redux.

In this article, we’ll look at how to use the useDispatch and useStore hooks in the React-Redux hooks API, and also look at performance and stale state issues.

useDispatch

We can use the useDispatch hook to get the dispatch function to dispatch actions to the store.

For example, we use useDispatch as follows:

import React from "react";
import ReactDOM from "react-dom";
import { Provider, useSelector, useDispatch } from "react-redux";
import { createStore } from "redux";

function count(state = 0, action) {
  switch (action.type) {
    case "INCREMENT":
      return state + 1;
    case "DECREMENT":
      return state - 1;
    default:
      return state;
  }
}

const store = createStore(count);

function App() {
  const count = useSelector(state => state);
  const dispatch = useDispatch();
  return (
    <div className="App">
      <button onClick={() => dispatch({ type: "INCREMENT" })}>Increment</button>
      <button onClick={() => dispatch({ type: "DECREMENT" })}>Decrement</button>
      <p>{count}</p>
    </div>
  );
}

const rootElement = document.getElementById("root");
ReactDOM.render(
  <Provider store={store}>
    <App />
  </Provider>,
  rootElement
);

In the code above, we called useDispatch in App to get the dispatch function so that we can dispatch actions from the store.

Then we create functions that call dispatch to pass into the onClick prop.

useStore

We can use the useStore hook to get the reference to the Redux store. It’s the same one that we passed into the Provider component.

This shouldn’t be used frequently since we aren’t supposed to access the store directly within a React app since it doesn’t update according to the React update cycle.

Stale Props and “Zombie Children”

Stale props mean that a selector function relies on a component’s props to extract data, a parent component would re-render and pass down new props as a result of an action, but the component’s selector functions execute before the component has a chance to re-render with those new props.

This causes outdated data to be displayed. in the child component or an error being thrown.

“Zombie child” refers to the cases where multiple nested connected components are mounted ina first pass, causing a child component to subscribe to the store before its parent. Then an action is dispatched that deletes data from the store. The parent component would stop rendering the child as a result.

Because the child subscribed to the store first, its subscription runs before the parent stops render. When it reads a value based on props, the data no longer exists. Then an error may be thrown when the extraction logic doesn’t check for the case of the missing data.

Therefore, we should rely on props in our selector function for extracting data.

connect adds the necessary subscription to the context provider and delays evaluating child subscriptions until the connected component has re-rendered. Putting a connected component in the component tree just above the component using useSelector will prevent the issues above.

Photo by Ezra Jeffrey-Comeau on Unsplash

Performance

useSelector will do a reference equality comparison of the selected value when running the selector function after an action is dispatched.

It’ll only re-render if the previous state is different from the current state. connect and useSelector doesn’t prevent the component from re-rendering because of its parent re-rendering.

To stop parent re-rendering from re-rendering the child, we can use memoization to prevent that.

For example, we can write the following:

import React from "react";
import ReactDOM from "react-dom";
import { Provider, useSelector, useDispatch } from "react-redux";
import { createStore } from "redux";

function count(state = 0, action) {
  switch (action.type) {
    case "INCREMENT":
      return state + 1;
    case "DECREMENT":
      return state - 1;
    default:
      return state;
  }
}

const store = createStore(count);

function App() {
  const count = useSelector(state => state);
  const dispatch = useDispatch();
  return (
    <div className="App">
      <button onClick={() => dispatch({ type: "INCREMENT" })}>Increment</button>
      <button onClick={() => dispatch({ type: "DECREMENT" })}>Decrement</button>
      <p>{count}</p>
    </div>
  );
}

App = React.memo(App);

const rootElement = document.getElementById("root");
ReactDOM.render(
  <Provider store={store}>
    <App />
  </Provider>,
  rootElement
);

In the code above, we added the React.memo call as follows:

App = React.memo(App);

to cache existing results and preventing re-render if the state remains the same.

Conclusion

We can use the useDispatch hook to get the dispatch function to update the store’s state.

There’s also a useStore hook to get a reference of the Redux store in our React components.

However, we shouldn’t access the store directly with useStore since we’re supposed to use useSelector to get the latest state from the store and use useDispatch to dispatch actions.

Also, we have to be aware of stale props from parent components and child components that have been removed because of state changes throwing errors and displaying incorrect data.

We should also memoize the state of components to cache them so that they don’t have to re-render when nothing changed.