Published on

Redux and Redux Toolkit (RTK)

Authors
  • avatar
    Name
    Sudhakar J
    Twitter

Modern Redux with Redux Toolkit (RTK) and TypeScript by Jamund Ferguson

Redux

  • Redux is a predictable state container for JavaScript apps.
  • It is a single store containing "global" state.

Dispatch

  • The Redux store has a method called dispatch.
  • The only way to update the state is to call store.dispatch() and pass in an action object.
  • The store will run its reducer function and save the new state value inside, and we can call getState() to retrieve the updated value.
store.dispatch({ type: 'counter/increment' })

console.log(store.getState())
// {value: 1}

Reducer

  • A reducer (also called a reducing function) is a function that accepts an accumulation and a value and returns a new accumulation. They are used to reduce a collection of values down to a single value.
  • In Redux, the accumulated value is the state object, and the values being accumulated are actions. Reducers calculate a new state given the previous state and an action. They must be pure functions—functions that return the exact same output for given inputs.

Why Use Redux?

  • When an application grows bigger, it may have to share some state between components.
  • This is where Redux comes into the picture. Being a state management library, Redux will basically store and manage all the application's states.

What is a "thunk"?

  • The word "thunk" is a programming term that means "a piece of code that does some delayed work". Rather than execute some logic now, we can write a function body or code that can be used to perform the work later.

  • For Redux specifically, "thunks" are a pattern of writing functions with logic inside that can interact with a Redux store's dispatch and getState methods.

const thunkFunction = (dispatch, getState) => {
  // logic here that can dispatch actions or read state
}

store.dispatch(thunkFunction)

What Makes Redux Predictable?

  • State is Read-only in Redux. What makes Redux predictable is that to make a change in the state of the application, we need to dispatch an action which describes what changes we want to make in the state.
//Empty Redux Store

import { configureStore } from '@reduxjs/toolkit'

export const store = configureStore({
  reducer: {},
})
// Wrap the app in <Provider> so any component in app can access the redux store
import React from 'react'
import ReactDOM from 'react-dom'
import './index.css'
import App from './App'
import { store } from './app/store'
import { Provider } from 'react-redux'

ReactDOM.render(
  <Provider store={store}>
    <App />
  </Provider>,
  document.getElementById('root')
)

Redux Workflow

Redux

Keeping data organized

  • To keep data organized slices are used.
  • A slice is the portion of Redux code that relates to a specific set of data and actions within the store‘s state.
  • A slice reducer is the reducer responsible for handling actions and updating the data for a given slice, so each slice gets it's updated state.

createslice() takes an object with three main options fields:

  • name: a string that will be used as the prefix for generated action types
  • initialState: the initial state of the reducer
  • reducers: an object where the keys are strings, and the values are "case reducer" functions that will handle specific actions
const productSlice = createSlice({
  name: 'product',
  initialState,
  reducers: {},
})

//You can export this and import them into the store.ts file to use the specific slice as needed.

Redux Hooks

  • Redux provided useSelector and useDispatch hooks.
import { TypedUseSelectorHook, useDispatch, useSelector } from 'react-redux'
import type { RootState, AppDispatch } from './store'

// Use throughout your app instead of plain `useDispatch` and `useSelector`
type DispatchFunc = () => AppDispatch
export const useAppDispatch: DispatchFunc = useDispatch
export const useAppSelector: TypedUseSelectorHook<RootState> = useSelector

Selector function.

  • A selector function is any function that accepts the Redux store state (or part of the state) as an argument, and returns data that is based on that state.
  • A selector function can be used anywhere you have access to the entire Redux root state value.
function TodoList() {
  // This anonymous arrow function is a selector!
  const todos = useSelector((state) => state.todos)
}