Adding Course Params to Redux
In this lesson, we're going to add Course params to Redux
Let's start centralizing course params. We can start by creating the model. Inside models, we can do it inside course.ts
file, and export interface CourseParams. We need sort of type string, and search of type string. This will be optional so we can add a question mark here. We need the pageIndex of type number, pageSize of type number and categories of type number. It's number because we're passing category id, so let's also make this optional.
Let's go to the courseSlice file now. We can create a function with the initial values of the courseParams. Let's call the function, getParams. We will return the pageIndex to be 1, pageSize to be 3, and by default, sorting option to be the title. Now inside the initialState, we can add courseParams; the value can be getParams. Inside reducers, we can create a method called setCourseParams. We will call this method whenever we choose any filter. This will have access to the state and the action. First of all, we will set the coursesLoaded to be false. After that, we will set state.courseParams; we can use a spread operator, and pass action.payload, and also make the pageIndex to be 1. We always want the pageIndex to start with 1.
We will make a courseParams object with this, but we need to shape it in a way that our server understands it. Let's create a new function called getAxiosParams. This will accept courseParams of type CourseParams. First of all, we will initialize params with the help of URLSearchParams. We can instantiate with new keyword. Now we can append all the course parameters to the params; we have the append method to do this. Let's start by appending pageIndex. The value will be courseParams.pageIndex. Since our queries should be strings, let's convert this to a string. Next is the pageSize. I can copy it and replace it with pageSize. Next is the sort with value courseParams.sort. Now categories and search are optional so we can check if we have courseParams.category. We can then append categoryId with value, courseParams.category. We need to convert it into a string as well. Finally for the search, let's check if courseParams.search, then append search.
Now inside the getCoursesAsync function, we can get all the params. We can use getAxiosParams function and we need to access the courseParams state. We can do it using thunkApi. Since we are not passing any parameter to this function, we can pass underscore and our second paramter will be thunkApi. This is very useful. We will see it in future lessons; but for now, it will give us access to the state, so we can use thunkAPI.getState().course.courseParams, and we can simply pass this to agent Courses list. Let's export this function now, from courseSlice.actions.
client/src/redux/slice/courseSlice.ts
xxxxxxxxxx
import {
createAsyncThunk,
createEntityAdapter,
createSlice,
} from '@reduxjs/toolkit'
import agent from '../../actions/agent'
import { Course, CourseParams } from '../../models/course'
import { PaginatedCourse } from '../../models/paginatedCourse'
import { RootState } from '../store/configureStore'
​
const coursesAdapter = createEntityAdapter<Course>()
​
function getAxiosParams(courseParams: CourseParams) {
const params = new URLSearchParams()
params.append('pageIndex', courseParams.pageIndex.toString())
params.append('pageSize', courseParams.pageSize.toString())
params.append('sort', courseParams.sort)
if (courseParams.category)
params.append('categoryId', courseParams.category.toString())
if (courseParams.search) params.append('search', courseParams.search)
return params
}
​
export const getCoursesAsync = createAsyncThunk<
PaginatedCourse | undefined,
void,
{ state: RootState }
>('course/getCoursesAsync', async (_, thunkAPI) => {
const params = getAxiosParams(thunkAPI.getState().course.courseParams)
try {
const response = await agent.Courses.list(params)
return response
} catch (err) {
console.log(err)
}
})
​
export const getCourseAsync = createAsyncThunk<
Course | undefined,
{ courseId: string }
>('course/getCourseAsync', async ({ courseId }, thunkAPI) => {
try {
return await agent.Courses.getById(courseId)
} catch (err) {
console.log(err)
}
})
​
function getParams() {
return {
pageIndex: 1,
pageSize: 3,
sort: 'title',
}
}
​
export const courseSlice = createSlice({
name: 'course',
initialState: coursesAdapter.getInitialState<any>({
coursesLoaded: false,
status: 'idle',
courseParams: getParams(),
}),
reducers: {
setCourseParams: (state, action) => {
state.coursesLoaded = false
state.courseParams = {
state.courseParams,
action.payload,
pageIndex: 1,
}
},
setPagination: (state, action) => {
state.pagination = action.payload
},
},
extraReducers: (builder) => {
builder.addCase(getCoursesAsync.pending, (state) => {
state.status = 'pendingCourses'
})
builder.addCase(getCoursesAsync.fulfilled, (state, action) => {
coursesAdapter.setAll(state, action.payload!.data)
state.status = 'idle'
state.coursesLoaded = true
})
builder.addCase(getCoursesAsync.rejected, (state) => {
state.status = 'idle'
})
builder.addCase(getCourseAsync.pending, (state) => {
state.status = 'pendingCourse'
})
builder.addCase(getCourseAsync.fulfilled, (state, action) => {
coursesAdapter.upsertOne(state, action.payload!)
state.status = 'idle'
})
builder.addCase(getCourseAsync.rejected, (state, action) => {
console.log(action.payload)
state.status = 'idle'
})
},
})
​
export const coursesSelector = coursesAdapter.getSelectors(
(state: RootState) => state.course,
)
​
export const { setCourseParams } = courseSlice.actions
This lesson preview is part of the The newline Guide to Fullstack ASP.NET Core and React course and can be unlocked immediately with a single-time purchase. Already have access to this course? Log in here.
Get unlimited access to The newline Guide to Fullstack ASP.NET Core and React with a single-time purchase.
