Pages

Showing posts with label RTK Queries. Show all posts
Showing posts with label RTK Queries. Show all posts

How to access the state using Redux RTK in react native app

 How to access the state using Redux RTK in React native app?

In our previous blogs, we have learned to create a simple app with React.js, replacing redux with the help of the react hook, and many other things. Now it's time to move ahead and learn something new. In today’s article, we will access the state using Redux RTK.


To get started, we have to install the Redux Toolkit package. In our previous blogs, we detailed the entire installation process for Redux Toolkit. But, since we want to share complete information with our novice React developers, let's start from scratch.


Step 1: Install the Redux Toolkit package

First of all, we have to install Redux Toolkit and React-redux within the project.


As Redux Toolkit is already installed in the project in Typescript format, we have to install react-Redux using the below command:



# NPM

npm install @reduxjs/toolkit react-redux

# Yarn

yarn add @reduxjs/toolkit react-redux



React Redux has a dependency on @types/react-redux so the type definition file of the package will be automatically installed with it.


Step 2: Create an API with customBaseQuery

As we are using Redux RTK queries in our React Native project, we can't figure out how to access the state without firing the query each time. So, it is mandatory to create an API with customBaseQuery using the below command.



const emptySplitApi = createApi({

  reducerPath: 'api',

  baseQuery: customBaseQuery(),

  endpoints: () => ({})

})



Step 3: Inject endpoints

The next step after creating APIs is to inject endpoints. You can insert endpoints in your application by the below written command. 



export const userApi = emptySplitApi.injectEndpoints({

  endpoints: (builder) => ({

    getUser: builder.query<User, GetUserInput>({

      query: (options) => ({

        query: getUserQuery,

        options: options

      })

    })

  }),

  overrideExisting: true

})



Step 4: Configure the Store:

It's quite simple to configure the store in a React native app, and you can do it by following these steps. Initially, you have to create a store folder and then create an index.js file in the store folder. After that, use connect() to link the components to the store and send the actions to the store to change it.



const persistConfig = {

  key: 'root',

  storage: AsyncStorage

}


const reducers = combineReducers({

  [emptySplitApi.reducerPath]: emptySplitApi.reducer

})


const persistedReducer = persistReducer(persistConfig, reducers)


export const store = configureStore({

  reducer: persistedReducer,

  middleware: (getDefaultMiddleware) => getDefaultMiddleware({ serializableCheck: false }).concat(emptySplitApi.middleware)

})



Step 5: Using Dispatch Hook

You can also use the Redux RTK useDispatch hook to send actions that change the state. Here is the command to use useDispatch:



import { useDispatch } from '@reduxjs/toolkit';


const MyComponent = () => {

  const dispatch = useDispatch();


  const addTodo = () => {

    dispatch({

      type: 'ADD_TODO',

      payload: {

        "My new to-do," text

    });

  };


  return (

    <View>

      <Button onPress={addTodo} title="Add Todo" />

    </View>

  );

};



Lastly, we have to make a call to the getUser API through the redux-generated hook whenever the application is opened. This is effective, and we will get the desired response.



const { data } = useGetUserQuery(input)



Now, we need to access the user data on another screen of our app without calling the API again (Redux should have cached or saved the data). 


Final thoughts

In conclusion, Redux RTK is the best tool that can be used to easily access the state of your React Native app. It is a great alternative to building a custom Redux store that can help you keep your codebase cleaner and more organized. With Redux RTK, you can access the state of your React Native app with ease, allowing you to quickly access the data you need.


How to Use RTK Queries in a React App?

Before we get into the technicality of using RTK Query in place of React query, let's understand the basics and know what actually RTK Query is.


RTK Query is nothing but an advanced tool to fetch data on the client side. It is basically a caching tool and it works similarly to React. The only good thing about RTK Query is that it directly integrates with Redux. When interacting with APIs, developers frequently use Redux with middleware modules like Thunk.


Adding RTK Query to Redux Toolkit is not mandatory, but when you combine both of them in a React project, it brings out the true power of Redux Toolkit. However, it's advisable to use the official Redux+JS template or the Redux+TS template to initialize a new app with React and Redux.


To help you learn, we've created a React App project with all of the code in the src folder. We will provide some best practices to follow when utilizing Redux Toolkit with React in addition to instructing you on how to use RTK queries in React apps.


Install the React-Rtk package:

To get it started, let's start with using the official Redux+JS template or Redux+TS template. It is way easier and faster to create a React app that uses Redux. This also prevents you from making mistakes.


Here are the complete steps to add Redux Toolkit to an old React project:

There are a thousand ways to learn React programming, but if you want to learn it from scratch, then you are on the right platform. Here are detailed instructions for configuring Redux Toolkit and RTK Query with React. You will be able to comprehend the intricacies of the Redux Toolkit.


Let's start with an NPM because most developers are familiar with it. You can also use any other package manager according to availability, as it will not affect the written code.


  1. Launch a New React App

Let's first initialize a new React app if you don't already have one before we begin fetching and installing the necessary dependencies.


Use this command to launch a new TypeScript-enabled React app.



# Redux + Plain JS template

npx create-react-app my-app --template redux


# Redux + TypeScript template

npx create-react-app my-app --template redux-typescript



The project will take a few minutes to get initiated.


  1. Install React-Redux and Redux Toolkit

First of all, you have to install Redux Toolkit and React-redux within the project.


As Redux Toolkit is already installed in the project in Typescript format so we only have to install react-Redux using the below command:



# NPM

npm install @reduxjs/toolkit react-redux

# Yarn

yarn add @reduxjs/toolkit react-redux



React Redux has a dependency on @types/react-redux so the type definition file of the package will be automatically installed with it.


  1. Create Redux Store

Create a redux folder inside the src folder, and within this redux folder, create a store.ts file.


Redux Toolkit is already written in Typescript, so we don’t need to worry about installing its type definition files separately.



import { configureStore } from '@reduxjs/toolkit'


export const store = configureStore({

  reducer: {}

})




There is no need to include configureStore in addition. 


  1. Define Root State

Extract RootState and AppDispatch  and export it directly from the store.ts file.


RootState and AppDispatch inferred from the store will update as you add state slices, API services, or modify middleware settings. 



import { configureStore } from '@reduxjs/toolkit'


export const store = configureStore({

  reducer: {}

})


// Infer the `RootState` and `AppDispatch` types from the store itself

export type RootState = ReturnType<typeof store.getstate>

export type AppDispatch = typeof store.dispatch



  1. Insert Redux Store 

Since the store is created, it must be provided to all application components.


Import ./redux/store and the <Provider> component from react-redux to the index.tsx file.


Wrap the app component in the provider component, then give the provider the store as a prop.



import React from 'react';

import ReactDOM from 'react-dom/client';

import './index.css';

import App from './App';

import reportWebVitals from './reportWebVitals';

// ? Import Provider from react-redux and store from ./redux/store

import { Provider } from 'react-redux';

import { store } from './redux/store';


const root = ReactDOM.createRoot(

  document.getElementById('root') as HTMLElement

);

root.render(

  <React.StrictMode>

    {/* ? Provide the store as prop */}

    <Provider store={store}>

      <App />

    </Provider>

  </React.StrictMode>

);



  1. Define the State Selector

The RootState and AppDispatch types that we defined in the store.ts file can be imported into each component, however, it is advised to create typed versions of the useDispatch and useSelector hooks to be used throughout your entire application. 


  1. Dispatch Typed Hooks

Create a new hooks.ts file within the redux folder ./src/redux.


Write the below code to add the snippets.



import { TypedUseSelectorHook, useDispatch, useSelector } from 'react-redux';

import type { RootState, AppDispatch } from './store';


// Use throughout your app instead of plain `useDispatch` and `useSelector`

export const useAppDispatch = () => useDispatch<appdispatch>();

export const useAppSelector: TypedUseSelectorHook<rootstate> = useSelector



  1. Create a Redux State Slice

After defining Hooks and State Selector now it’s time to create our first redux state slice.


Create a features directory Inside the redux folder to house all our slices.


Create a new file with the name: src/redux/features/products/authSlice.ts.


Copy and paste the below code in the authSlice.ts file.


import { createSlice, PayloadAction } from '@reduxjs/toolkit';


export interface IUser {

  _id: string;

  name: string;

  email: string;

  photo: string;

  role: string;

  provider?: string;

  active?: boolean;

  verified?: boolean;

  createdAt: Date;

  updatedAt: Date;

  __v: number;

  id: string;

}


interface AuthState {

  user?: IUser | null;

}


const initialState: AuthState = {

  user: null,

};


export const authSlice = createSlice({

  name: 'authSlice',

  initialState,

  reducers: {

    // ? Logout the user by returning the initial state

    logout: () => initialState,

    // Save the user's info

    userInfo: (state, action: PayloadAction<authstate>) => {

      // Redux Toolkit allows us to write "mutating" logic in reducers. It

      // doesn't actually mutate the state because it uses the Immer library,

      // which detects changes to a "draft state" and produces a brand new

      // immutable state based off those changes

      state.user = action.payload.user;

    },

  },

});


export const { logout, userInfo } = authSlice.actions;

// ? Export the authSlice.reducer to be included in the store.

export default authSlice.reducer;




Those who have used Redux code in the past must know that it requires mentioning all state updates immutably by making copies of the state.


Redux Toolkit gives us the luxury of directly mutating any state.


  1. Add Reducer of the Redux State Slice

In the next step, we will import the reducer function.

To do this, we will export the authSlice.ts into the store and add it to the reducers object.


By defining the authUser field inside of the reducer object, we can communicate to the store that the authReducer function should be used to manage any updates to that state.


import { configureStore } from '@reduxjs/toolkit';

// ? import authReducer from authSlice

import authReducer from './features/authSlice'


export const store = configureStore({

  reducer: {

    // ? Add the authReducer to the reducer object

    authUser: authReducer

  },

// ? show the devTools only in development

devTools: process.env.NODE_ENV !== 'production',

});


export type RootState = ReturnType<typeof store.getstate>;

export type AppDispatch = typeof store.dispatch;




  1. Add RTK Query

RTK Query will help us retrieve API data from the cache. It is designed on top of the Redux Toolkit and uses its APIs for implementation.


It is not required to use RTK Query with Redux Toolkit; however, it is highly recommended to combine both Redux Toolkit and RTK Query in your project if you will be managing both local state and API data. While it is not required to use RTK Query with Redux Toolkit, it is highly recommended to do so. 


You are free to make use of other API state management tools such as React Query; however, using Redux Toolkit to get it set up and operational can be a real pain in the rear.


Because of this, the Redux team came to the conclusion that it would be beneficial to develop RTK Query, which has a user interface that is analogous to that of React Query but is more compatible with Redux Toolkit and is less complicated to operate.


  1. Create an API Service

It is necessary to create an API service within the redux directory. 

Create an API file named src/redux/api/products/productAPI.ts


An example of a CRUD operation performed with RTK Query is shown below. In this example, I am retrieving all of the products, obtaining a single product, updating a single product, and deleting a single product.


createAPI will take a single configuration object that may have any of the following parameters if it is provided.


import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/dist/query/react';


type IProduct = {

  _id: string;

  name: string;

  avgRating: number;

  numRating: number;

  price: number;

  description: string;

  countInStock: number;

  quantity?: number;

  imageCover: string;

  images: string[];

  category: string;

  createdAt: Date;

  updatedAt: Date;

  slug: string;

  id: string;

};


export const productApi = createApi({

  reducerPath: 'productApi',

  baseQuery: fetchBaseQuery({ baseUrl: 'http://localhost:8000/api/' }),

  tagTypes: ['Products'],

  endpoints: (builder) => ({

    // ? Query: Get All Products

    getProducts: builder.query<iproduct[], void>({

      query() {

        return 'products';

      },

      providesTags: (result) =>

        result

          ? [

              ...result.map(({ id }) => ({

                type: 'Products' as const,

                id,

              })),

              { type: 'Products', id: 'LIST' },

            ]

          : [{ type: 'Products', id: 'LIST' }],

      // ? Transform the result to prevent nested data

      transformResponse: (response: { data: { products: IProduct[] } }) =>

        response.data.products,

    }),

    // ? Query: Get a single product

    getProduct: builder.query<iproduct, string>({

      query(id) {

        return `products/${id}`;

      },

      transformResponse: (

        response: { data: { product: IProduct } },

        args,

        meta

      ) => response.data.product,

      providesTags: (result, error, id) => [{ type: 'Products', id }],

    }),

    // ? Mutation: Create a product

    createProduct: builder.mutation<iproduct, formdata>({

      query(data) {

        return {

          url: 'products',

          method: 'POST',

          credentials: 'include',

          body: data,

        };

      },

      invalidatesTags: [{ type: 'Products', id: 'LIST' }],

      transformResponse: (response: { data: { product: IProduct } }) =>

        response.data.product,

    }),

    // ? Mutation: Update Product

    updateProduct: builder.mutation<

      IProduct,

      { id: string; formData: FormData }

    >({

      query({ id, formData }) {

        return {

          url: `products/${id}`,

          method: 'PATCH',

          credentials: 'include',

          body: formData,

        };

      },

      invalidatesTags: (result, error, { id }) =>

        result

          ? [

              { type: 'Products', id },

              { type: 'Products', id: 'LIST' },

            ]

          : [{ type: 'Products', id: 'LIST' }],

      transformResponse: (response: { data: { product: IProduct } }) =>

        response.data.product,

    }),

    // ? Mutation: Delete product

    deleteProduct: builder.mutation<null, string>({

      query(id) {

        return {

          url: `products/${id}`,

          method: 'DELETE',

          credentials: 'include',

        };

      },

      invalidatesTags: [{ type: 'Products', id: 'LIST' }],

    }),

  }),

});


export const {

  useCreateProductMutation,

  useUpdateProductMutation,

  useDeleteProductMutation,

  useGetProductsQuery,

  useGetProductQuery,

  usePrefetch,

} = productsApi;



  1. Adding the final API Service to the Redux Store

RTK Query will produce what is known as a "slice reducer" from the productAPI, which is intended to be added to the Redux root reducer.


Additionally, a specialised middleware will be generated, and the middleware parameter will need to be updated to include it.


import { configureStore } from '@reduxjs/toolkit';

// ? import authReducer from authSlice

import authReducer from './features/authSlice';

import { productsApi } from './api/products/productAPI';


export const store = configureStore({

  reducer: {

    // ? Add the authReducer to the reducer object

    authUser: authReducer,

    [productsApi.reducerPath]: productsApi.reducer,

  },

  devTools: process.env.NODE_ENV !== 'production',

   // Adding the api middleware enables caching, invalidation, polling,

   // and other useful features of `rtk-query`.

  middleware: (getDefaultMiddleware) =>

    getDefaultMiddleware({}).concat([productsApi.middleware]),

});


export type RootState = ReturnType<typeof store.getstate>;

export type AppDispatch = typeof store.dispatch;



Final thoughts:

RTK Query implementation in a React app is critical for creating efficient and powerful apps. Developers can make applications that work well and are easy to maintain by using the query syntax and providing the necessary data. Even though the process can be difficult, the end result has many benefits and can help developers make apps with more features that can be used for a wide range of tasks. With the right guidance, developers can easily and effectively implement RTK Query in a React app and take their applications to the next level.


Make new Model/Controller/Migration in Laravel

  In this article, we have included steps to create a model and controller or resource controller with the help of command line(CLI). Here w...