npx create-react-app my-redux-app --template typescript
cd my-redux-app
npm install @reduxjs/toolkit react-redux
npm install ajv@^8.0.0
npm install antd
- package.json
{
"name": "my-redux-app",
"version": "0.1.0",
"private": true,
"dependencies": {
"@reduxjs/toolkit": "^2.3.0",
"@testing-library/jest-dom": "^5.17.0",
"@testing-library/react": "^13.4.0",
"@testing-library/user-event": "^13.5.0",
"@types/jest": "^27.5.2",
"@types/node": "^16.18.120",
"@types/react": "^18.3.12",
"@types/react-dom": "^18.3.1",
"ajv": "^8.17.1",
"antd": "^5.22.2",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react-redux": "^9.1.2",
"react-scripts": "5.0.1",
"typescript": "^4.9.5",
"web-vitals": "^2.1.4"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject"
},
"eslintConfig": {
"extends": [
"react-app",
"react-app/jest"
]
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
}
}
项目结构:
- src/store/counter.ts
import { createSlice, PayloadAction } from '@reduxjs/toolkit'
// 这是一个简单的redux使用示例,可以参考
export interface CounterState {
value: number;
status: 'idle' | 'loading' | 'failed';
list: Array<string>;
}
const initialState: CounterState = {
value: 0,
status: 'idle',
list: [],
};
export const counterSlice = createSlice({
name: 'counter',
initialState,
reducers: {
increment: (state: CounterState) => {
// 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;
state.list.push(`${state.value}`);
},
decrement: (state: CounterState) => {
state.value -= 1;
state.list.pop();
},
incrementByAmount: (state: CounterState, action: PayloadAction<number>) => {
state.value += action.payload
state.list.push(`${state.value}`);
},
},
})
// Action creators are generated for each case reducer function
export const { increment, decrement, incrementByAmount } = counterSlice.actions
export default counterSlice.reducer
- src/store/store.ts
import { configureStore } from '@reduxjs/toolkit';
import counterSlice from "./counter";
export const store = configureStore({
reducer: {
counter: counterSlice,
},
middleware: (getDefaultMiddleware) =>
getDefaultMiddleware({
serializableCheck: false,
}),
});
// Infer the `RootState` and `AppDispatch` types from the store itself
export type RootState = ReturnType<typeof store.getState>;
// Inferred type: {posts: PostsState, comments: CommentsState, users: UsersState}
export type AppDispatch = typeof store.dispatch;
// 监听store的变化
store.subscribe(() => {
// const state = store.getState() as RootState;
// console.log(state);
});
- App.tsx
// src/App.tsx
import React from 'react';
import { useSelector, useDispatch } from 'react-redux';
import { RootState } from './store/store';
import { increment, decrement, incrementByAmount } from './store/counter';
import {Button} from 'antd';
const App: React.FC = () => {
const count = useSelector((state: RootState) => state.counter.value);
const dispatch = useDispatch();
return (
<div style={{ textAlign: 'center', marginTop: '20px' }}>
<h1>计数器: {count}</h1>
<Button onClick={() => dispatch(increment())}>增加</Button>
<Button onClick={() => dispatch(decrement())}>减少</Button>
<Button onClick={() => dispatch(incrementByAmount(5))}>增加5</Button>
</div>
);
};
export default App;
- index.tsx
// src/index.tsx
import React from 'react';
import ReactDOM from 'react-dom/client';
import { Provider } from 'react-redux';
import { store } from './store/store';
import App from './App';
const root = ReactDOM.createRoot(
document.getElementById('root') as HTMLElement
);
root.render(
<React.StrictMode>
<Provider store={store}>
<App />
</Provider>
</React.StrictMode>
);