Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Revert some of the 2.0 related changes #128

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,89 +1,100 @@
// This file demonstrates typical usage of Redux Toolkit's createSlice function
// for defining reducer logic and actions, as well as related thunks and selectors.

import type { PayloadAction } from "@reduxjs/toolkit"
import { createAppSlice } from "../../app/createAppSlice"
import type { AppThunk } from "../../app/store"
import { createAsyncThunk, createSlice } from "@reduxjs/toolkit"
import type { AppThunk, RootState } from "../../app/store"
import { fetchCount } from "./counterAPI"

export interface CounterSliceState {
// Define the TS type for the counter slice's state
export interface CounterState {
value: number
status: "idle" | "loading" | "failed"
}

const initialState: CounterSliceState = {
// Define the initial value for the slice state
const initialState: CounterState = {
value: 0,
status: "idle",
}

// If you are not using async thunks you can use the standalone `createSlice`.
export const counterSlice = createAppSlice({
// Slices contain Redux reducer logic for updating state, and
// generate actions that can be dispatched to trigger those updates.
export const counterSlice = createSlice({
name: "counter",
// `createSlice` will infer the state type from the `initialState` argument
initialState,
// The `reducers` field lets us define reducers and generate associated actions
reducers: create => ({
increment: create.reducer(state => {
reducers: {
increment: state => {
// 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.value += 1
}),
decrement: create.reducer(state => {
},
decrement: state => {
state.value -= 1
}),
// Use the `PayloadAction` type to declare the contents of `action.payload`
incrementByAmount: create.reducer(
(state, action: PayloadAction<number>) => {
},
// Use the PayloadAction type to declare the contents of `action.payload`
incrementByAmount: (state, action: PayloadAction<number>) => {
state.value += action.payload
},
},
// The `extraReducers` field lets the slice handle actions defined elsewhere,
// including actions generated by createAsyncThunk or in other slices.
extraReducers: builder => {
builder
// Handle the action types defined by the `incrementAsync` thunk defined below.
// This lets the slice reducer update the state with request status and results.
.addCase(incrementAsync.pending, state => {
state.status = "loading"
})
.addCase(incrementAsync.fulfilled, (state, action) => {
state.status = "idle"
state.value += action.payload
},
),
// The function below is called a thunk and allows us to perform async logic. It
// can be dispatched like a regular action: `dispatch(incrementAsync(10))`. This
// will call the thunk with the `dispatch` function as the first argument. Async
// code can then be executed and other actions can be dispatched. Thunks are
// typically used to make async requests.
incrementAsync: create.asyncThunk(
async (amount: number) => {
const response = await fetchCount(amount)
// The value we return becomes the `fulfilled` action payload
return response.data
},
{
pending: state => {
state.status = "loading"
},
fulfilled: (state, action) => {
state.status = "idle"
state.value += action.payload
},
rejected: state => {
state.status = "failed"
},
},
),
}),
// You can define your selectors here. These selectors receive the slice
// state as their first argument.
selectors: {
selectCount: counter => counter.value,
selectStatus: counter => counter.status,
})
.addCase(incrementAsync.rejected, state => {
state.status = "failed"
})
},
})

// Action creators are generated for each case reducer function.
export const { decrement, increment, incrementByAmount, incrementAsync } =
counterSlice.actions
// Export the generated action creators for use in components
export const { increment, decrement, incrementByAmount } = counterSlice.actions

// Selectors returned by `slice.selectors` take the root state as their first argument.
export const { selectCount, selectStatus } = counterSlice.selectors
// Export the slice reducer for use in the store configuration
export default counterSlice.reducer

// We can also write thunks by hand, which may contain both sync and async logic.
// Selector functions allows us to select a value from the Redux root state.
// Selectors can also be defined inline in the `useSelector` call
// in a component, or inside the `createSlice.selectors` field.
export const selectCount = (state: RootState) => state.counter.value
export const selectStatus = (state: RootState) => state.counter.status

// The function below is called a thunk, which can contain both sync and async logic
// that has access to both `dispatch` and `getState`. They can be dispatched like
// a regular action: `dispatch(incrementIfOdd(10))`.
// Here's an example of conditionally dispatching actions based on current state.
export const incrementIfOdd =
(amount: number): AppThunk =>
(dispatch, getState) => {
export const incrementIfOdd = (amount: number): AppThunk => {
return (dispatch, getState) => {
const currentValue = selectCount(getState())

if (currentValue % 2 === 1 || currentValue % 2 === -1) {
if (currentValue % 2 === 1) {
dispatch(incrementByAmount(amount))
}
}
}

// Thunks are commonly used for async logic like fetching data.
// The `createAsyncThunk` method is used to generate thunks that
// dispatch pending/fulfilled/rejected actions based on a promise.
// In this example, we make a mock async request and return the result.
// The `createSlice.extraReducers` field can handle these actions
// and update the state with the results.
export const incrementAsync = createAsyncThunk(
"counter/fetchCount",
async (amount: number) => {
const response = await fetchCount(amount)
// The value we return becomes the `fulfilled` action payload
return response.data
},
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
// This file has the exact same functionality as `counterSlice.ts`,
// but it uses the newest features from Redux Toolkit 2.0.
// These are optional, but may simplify some of your code.

import type { PayloadAction } from "@reduxjs/toolkit"
import { createAppSlice } from "../../app/createAppSlice"
import type { AppThunk } from "../../app/store"
import { fetchCount } from "./counterAPI"

export interface CounterSliceState {
value: number
status: "idle" | "loading" | "failed"
}

const initialState: CounterSliceState = {
value: 0,
status: "idle",
}

// If you are not using async thunks you can use the standalone `createSlice`.
export const counterSlice = createAppSlice({
name: "counter",
// `createSlice` will infer the state type from the `initialState` argument
initialState,
// The `reducers` field lets us define reducers and generate associated actions
reducers: create => ({
increment: create.reducer(state => {
// 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.value += 1
}),
decrement: create.reducer(state => {
state.value -= 1
}),
// Use the `PayloadAction` type to declare the contents of `action.payload`
incrementByAmount: create.reducer(
(state, action: PayloadAction<number>) => {
state.value += action.payload
},
),
// The function below is called a thunk and allows us to perform async logic. It
// can be dispatched like a regular action: `dispatch(incrementAsync(10))`. This
// will call the thunk with the `dispatch` function as the first argument. Async
// code can then be executed and other actions can be dispatched. Thunks are
// typically used to make async requests.
incrementAsync: create.asyncThunk(
async (amount: number) => {
const response = await fetchCount(amount)
// The value we return becomes the `fulfilled` action payload
return response.data
},
{
pending: state => {
state.status = "loading"
},
fulfilled: (state, action) => {
state.status = "idle"
state.value += action.payload
},
rejected: state => {
state.status = "failed"
},
},
),
}),
// You can define your selectors here. These selectors receive the slice
// state as their first argument.
selectors: {
selectCount: counter => counter.value,
selectStatus: counter => counter.status,
},
})

// Action creators are generated for each case reducer function.
export const { decrement, increment, incrementByAmount, incrementAsync } =
counterSlice.actions

// Selectors returned by `slice.selectors` take the root state as their first argument.
export const { selectCount, selectStatus } = counterSlice.selectors

// We can also write thunks by hand, which may contain both sync and async logic.
// Here's an example of conditionally dispatching actions based on current state.
export const incrementIfOdd =
(amount: number): AppThunk =>
(dispatch, getState) => {
const currentValue = selectCount(getState())

if (currentValue % 2 === 1 || currentValue % 2 === -1) {
dispatch(incrementByAmount(amount))
}
}
Original file line number Diff line number Diff line change
@@ -1,78 +1,92 @@
import { createAppSlice } from "../../app/createAppSlice"
// This file demonstrates typical usage of Redux Toolkit's createSlice function
// for defining reducer logic and actions, as well as related thunks and selectors.

import { createAsyncThunk, createSlice } from "@reduxjs/toolkit"
import { fetchCount } from "./counterAPI"

// Define the initial value for the slice state
const initialState = {
value: 0,
status: "idle",
}

// If you are not using async thunks you can use the standalone `createSlice`.
export const counterSlice = createAppSlice({
// Slices contain Redux reducer logic for updating state, and
// generate actions that can be dispatched to trigger those updates.
export const counterSlice = createSlice({
name: "counter",
// `createSlice` will infer the state type from the `initialState` argument
initialState,
// The `reducers` field lets us define reducers and generate associated actions
reducers: create => ({
increment: create.reducer(state => {
reducers: {
increment: state => {
// 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.value += 1
}),
decrement: create.reducer(state => {
},
decrement: state => {
state.value -= 1
}),
// Use the `PayloadAction` type to declare the contents of `action.payload`
incrementByAmount: create.reducer((state, action) => {
},
// Use the PayloadAction type to declare the contents of `action.payload`
incrementByAmount: (state, action) => {
state.value += action.payload
}),
// The function below is called a thunk and allows us to perform async logic. It
// can be dispatched like a regular action: `dispatch(incrementAsync(10))`. This
// will call the thunk with the `dispatch` function as the first argument. Async
// code can then be executed and other actions can be dispatched. Thunks are
// typically used to make async requests.
incrementAsync: create.asyncThunk(
async amount => {
const response = await fetchCount(amount)
// The value we return becomes the `fulfilled` action payload
return response.data
},
{
pending: state => {
state.status = "loading"
},
fulfilled: (state, action) => {
state.status = "idle"
state.value += action.payload
},
rejected: state => {
state.status = "failed"
},
},
),
}),
// You can define your selectors here. These selectors receive the slice
// state as their first argument.
selectors: {
selectCount: counter => counter.value,
selectStatus: counter => counter.status,
},
},
// The `extraReducers` field lets the slice handle actions defined elsewhere,
// including actions generated by createAsyncThunk or in other slices.
extraReducers: builder => {
builder
// Handle the action types defined by the `incrementAsync` thunk defined below.
// This lets the slice reducer update the state with request status and results.
.addCase(incrementAsync.pending, state => {
state.status = "loading"
})
.addCase(incrementAsync.fulfilled, (state, action) => {
state.status = "idle"
state.value += action.payload
})
.addCase(incrementAsync.rejected, state => {
state.status = "failed"
})
},
})

// Action creators are generated for each case reducer function.
export const { decrement, increment, incrementByAmount, incrementAsync } =
counterSlice.actions
// Export the generated action creators for use in components
export const { increment, decrement, incrementByAmount } = counterSlice.actions

// Selectors returned by `slice.selectors` take the root state as their first argument.
export const { selectCount, selectStatus } = counterSlice.selectors
// Export the slice reducer for use in the store configuration
export default counterSlice.reducer

// We can also write thunks by hand, which may contain both sync and async logic.
// Here's an example of conditionally dispatching actions based on current state.
export const incrementIfOdd = amount => (dispatch, getState) => {
const currentValue = selectCount(getState())
// Selector functions allows us to select a value from the Redux root state.
// Selectors can also be defined inline in the `useSelector` call
// in a component, or inside the `createSlice.selectors` field.
export const selectCount = (state) => state.counter.value
export const selectStatus = (state) => state.counter.status

if (currentValue % 2 === 1 || currentValue % 2 === -1) {
dispatch(incrementByAmount(amount))
// The function below is called a thunk, which can contain both sync and async logic
// that has access to both `dispatch` and `getState`. They can be dispatched like
// a regular action: `dispatch(incrementIfOdd(10))`.
// Here's an example of conditionally dispatching actions based on current state.
export const incrementIfOdd = (amount) => {
return (dispatch, getState) => {
const currentValue = selectCount(getState())
if (currentValue % 2 === 1) {
dispatch(incrementByAmount(amount))
}
}
}

// Thunks are commonly used for async logic like fetching data.
// The `createAsyncThunk` method is used to generate thunks that
// dispatch pending/fulfilled/rejected actions based on a promise.
// In this example, we make a mock async request and return the result.
// The `createSlice.extraReducers` field can handle these actions
// and update the state with the results.
export const incrementAsync = createAsyncThunk(
"counter/fetchCount",
async (amount) => {
const response = await fetchCount(amount)
// The value we return becomes the `fulfilled` action payload
return response.data
},
)
Loading