Install Redux Toolkit and React-Redux
npm install @reduxjs/toolkit react-redux
Create a Redux Store
app/store.js
import { configureStore } from '@reduxjs/toolkit'
export const store = configureStore({
reducer: {},
})
Provide the Redux Store to React
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')
)
Create a Redux State Slice
src/features/counter/counterSlice.js
import { createSlice } from '@reduxjs/toolkit'
const initialState = {
value: 0,
}
export const counterSlice = createSlice({
name: 'counter',
initialState,
reducers: {
increment: (state) => {
state.value += 1
},
decrement: (state) => {
state.value -= 1
},
incrementByAmount: (state, action) => {
state.value += action.payload
},
},
})
// Action creators are generated for each case reducer function
export const { increment, decrement, incrementByAmount } = counterSlice.actions
export default counterSlice.reducer
Add Slice Reducers to the Store
import { configureStore } from '@reduxjs/toolkit'
import counterReducer from '../features/counter/counterSlice'
export const store = configureStore({
reducer: {
counter: counterReducer,
},
})
Use Redux State and Actions in React Components
features/counter/Counter.js
import React from 'react'
import { useSelector, useDispatch } from 'react-redux'
import { decrement, increment } from './counterSlice'
export function Counter() {
const count = useSelector((state) => state.counter.value)
const dispatch = useDispatch()
return (
<div>
<div>
<button
aria-label="Increment value"
onClick={() => dispatch(increment())}
>
Increment
</button>
<span>{count}</span>
<button
aria-label="Decrement value"
onClick={() => dispatch(decrement())}
>
Decrement
</button>
</div>
</div>
)
}
RTK Query
APIs
import createApi
import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react'
// Define a service using a base URL and expected endpoints
export const ImagesApi = createApi({
reducerPath: 'imagesApi',
baseQuery: fetchBaseQuery({ baseUrl: 'https://jsonplaceholder.typicode.com/' }),
endpoints: (builder) => ({
getImages: builder.query({
query: () => `/users`,
}),
}),
})
export const { useGetImagesQuery } = ImagesApi;
Configure the store
import {configureStore} from '@reduxjs/toolkit';
import counterReducer from '../features/counter/counterSlice';
import { ImagesApi } from '../Apis/ImagesApi';
export default configureStore({
reducer:{
counter: counterReducer,
[ImagesApi.reducerPath]: ImagesApi.reducer
},
middleware: (getDefaultMiddleware)=>getDefaultMiddleware().concat(ImagesApi.middleware)
})
Use Hooks in Components
import { useGetImagesQuery } from "./Apis/ImagesApi";
let Photos=()=>{
const {data, error, isLoading, isSuccess} =useGetImagesQuery();
console.log(data);
return(
<>
{error && "Something wrong"}
<h1>Images collection</h1>
{isLoading && "Loading.."}
{
isSuccess && data.map((value, index, item)=>{
return(
<div key={value.id}>
<h4>{value.name}</h4>
</div>
)
})
}
</>
)
}
export default Photos;
Mutations
// src/taskApi.js
createApi({
reducerPath: "tasksApi",
baseQuery: fetchBaseQuery({
baseUrl: "http://localhost:5000/"
}),
tagTypes: ["Task"],
endpoints: (builder) => ({
tasks: builder.query({
query: () => "/tasks",
providesTags: ["Task"]
}),
addTask: builder.mutation({
query: (task) => ({
url: "/tasks",
method: "POST",
body: task
}),
invalidatesTags: ["Task"]
}),
updateTask: builder.mutation({
query: ({ id, ...rest }) => ({
url: `/tasks/${id}`,
method: "PUT",
body: rest
}),
invalidatesTags: ["Task"]
}),
deleteTask: builder.mutation({
query: (id) => ({
url: `/tasks/${id}`,
method: "DELETE"
}),
invalidatesTags: ["Task"]
})
})
});