- 简化配置
- 内置 Immer 包,可以直接修改数据,而不用在进行 immutable(当然核心还是 immutable,但写法上不需要再immutable,因为 immer 包会帮助我们自动进行)
- 内置 thunk 包,可以更好的封装异步操作
- 内置了 redux-devtools
npm install @reduxjs/toolkit react-redux --save
import { configureStore } from '@reduxjs/toolkit'
export default configureStore({
reducer: {},
})
import store from './app/store'
import { Provider } from 'react-redux'
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById('root')
)
import { createSlice } from '@reduxjs/toolkit'
const initialState = {
username: ''
}
export const userSlice = createSlice({
name: 'counter',
initialState,
reducers: {
login(state, action) {
state.username = action.payload
},
logout(state) {
state.username = ''
}
},
})
export const { login, logout } = userSlice.actions
export default userSlice.reducer
import userReducer from '../components/user/user.slice.js'
export default configureStore({
reducer: {
user: userReducer
},
})
- 如
src/components/user/user.js
import React from 'react'
import { useSelector, useDispatch } from 'react-redux'
import { login, logout } from './user.slice'
export function Counter() {
const username = useSelector(state => state.user.username)
const dispatch = useDispatch()
return (
<div>
<div>username: {username}</div>
<div>
<input onChange={e => dispatch(login(e.target.value))} />
<button
onClick={() => dispatch(logout())}
>logout</button>
</div>
</div>
)
}
import { configureStore } from '@reduxjs/toolkit'
export default configureStore({
reducer: {},
})
export type RootState = ReturnType<typeof store.getState>
export type AppDispatch = typeof store.dispatch
import { TypedUseSelectorHook, useDispatch, useSelector } from 'react-redux'
import type { RootState, AppDispatch } from './store'
export const useAppDispatch = () => useDispatch<AppDispatch>()
export const useAppSelector: TypedUseSelectorHook<RootState> = useSelector
import store from './app/store'
import { Provider } from 'react-redux'
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById('root')
)
import { createSlice, PayloadAction } from '@reduxjs/toolkit'
interface UserState {
username: string;
}
const initialState: UserState = {
username: ''
}
export const userSlice = createSlice({
name: 'user',
initialState,
reducers: {
login(state, action: PayloadAction<string>) {
state.username = action.payload
},
logout(state) {
state.username = ''
}
}
})
export const { login, logout } = userSlice.actions
export default userSlice.reducer
import userReducer from '../components/user/user.slice.js'
export default configureStore({
reducer: {
user: userReducer
},
})
- 如
src/components/user/user.js
import React from 'react'
import { useAppDispatch, useAppSelector } from '../../store/hooks'
import { login, logout } from './user.slice'
export function Counter() {
const username = useAppSelector(state => state.user.username)
const dispatch = useAppDispatch()
return (
<div>
<div>username: {username}</div>
<div>
<input onChange={e => dispatch(login(e.target.value))} />
<button
onClick={() => dispatch(logout())}
>logout</button>
</div>
</div>
)
}
import { createAsyncThunk } from '@reduxjs/toolkit'
import axios from 'axios'
export const getName = createAsyncThunk(
'user/getName',
async () => {
const { data: { name } } = await axios.get('/api/getName')
return name
}
)
export const setName = createAsyncThunk(
'user/setName',
async (name) => {
const { status } = await axios.post('/api/setName', { name })
if ( (status >= 200 && status <= 299) || status === 301 ) {
return
}
throw `服务器错误:${status}`
}
)
import { getName, setName } from './async.js'
export const userSlice = createSlice({
name: 'user',
initialState,
reducers: {
login(state, action: PayloadAction<string>) {
state.username = action.payload
},
logout(state) {
state.username = ''
}
},
extraReducers: {
[getName.fulfilled]: (state, action) => {
state.username = action.payload
},
[setName.fulfilled]: (state, action) => {
state.username = action.payload
},
[setName.rejected]: (state, action) => {
consle.log(action.payload)
}
}
})
dispatch(getName())
dispatch(setName('kinmgusi'))