创建文件
这是一个经典的Redux模版,如果你对redux比较陌生,可以放弃使用 redux
,选择适合自己的代码习惯
此示例为基于Redux的高阶组件,如简单todolist可不遵循下方示例
- 在SRC文件夹中,创建一个新文件夹,这里示例
TODOLIST
- 在
todolist
下创建如下对应目录
│ todoPage.tsx //入口页面,内含todolist和子组件todoControl
│ todoControl.tsx //操控组件
│ todoList.tsx //列表控件
│
└─service //每个业务文件夹下必含该文件夹及其下属文件
todoAction.ts //主要是功能处理
todoReducers.ts //判断处理
todoTypes.ts //内含有枚举,辅助reducer
书写代码
主要功能:从网络中获取现有todolist,并且赋予其增删功能(增删暂为本地)
确定好功能后,大概有这几种操作
export enum ETodoTypes {
TODO_FETCH_LOADING = "TODO_FETCH_LOADING", //开始网络获取
TODO_FETCH_SUCCESS = "TODO_FETCH_SUCCESS", //网络获取成功
TODO_FETCH_ERROR = "TODO_FETCH_ERROR", //网络获取失败
TODO_FETCH_REFUSH ="TODO_FETCH_REFUSH",
TODO_ADD_ITEM = 'TODO_ADD_ITEM', //本地增加一条
TODO_REMOVE_ITEM ='TODO_REMOVE_ITEM', //本地移除一条
}
将他们书写在todoTypes.ts
中,并将该文件引入 src/store/types/index.ts
中,方便使用
export * from "../../todolist/service/todoTypes";
todoReducers.ts书写
引入刚刚写好的ETodoTypes
和store
目录下IInitialState
import { ETodoTypes, IInitialState } from "../../store/types";
interface ITodo {
userId: number,
id: number,
title: string,
completed: boolean
}
interface INITSTATE {
isLoading: boolean,
todolist: Array<ITodo>
}
const initialState: INITSTATE = {
isLoading: true,
todolist: []
};
export const todoReducer = (state = initialState, action: IInitialState) => {
switch (action.type) {
case ETodoTypes.TODO_FETCH_LOADING:
return {
...state,
isLoading: true
};
case ETodoTypes.TODO_FETCH_SUCCESS:
return {
...state,
isLoading: false,
todolist: action.payload as Array<ITodo>
};
case ETodoTypes.TODO_FETCH_REFUSH:
return {
...state,
isLoading: false,
todolist: action.payload as Array<ITodo>
};
case ETodoTypes.TODO_FETCH_ERROR:
return {
...state,
isLoading: false,
todolist: action.payload as Array<ITodo>
};
case ETodoTypes.TODO_ADD_ITEM:
return {
...state,
isLoading: false,
todolist: action.payload as Array<ITodo>
};
case ETodoTypes.TODO_REMOVE_ITEM:
return {
...state,
isLoading: false,
todolist: action.payload as Array<ITodo>
};
default:
return state;
}
};
将该文件引入 src/store/reducers/index.ts
中
export * from "../../todolist/service/todoReducers";
将写好的reducer
引入/store/index.ts
import { createStore, combineReducers, applyMiddleware } from "redux";
import thunkMiddleware from "redux-thunk";
import { composeWithDevTools } from "redux-devtools-extension";
import { userReducer,todoReducer } from "./reducers";
// import { chatReducer } from "./chat/reducers";
const rootReducer = combineReducers({
user: userReducer,
todo:todoReducer
});
export type AppState = ReturnType<typeof userReducer>;
export const configureStore = () => {
const middlewares = [thunkMiddleware];
const middleWareEnhancer = applyMiddleware(...middlewares);
const store = createStore(
rootReducer,
composeWithDevTools(middleWareEnhancer)
);
return store;
};
到这里,恭喜你,你已经完成了一大步,剩下的,就可以开心写代码了
接下来,我们在todoAction
中为todoList
书写三个功能
import { Dispatch } from "redux";
import axios from "../../utils/http";
import { ETodoTypes } from "../../store/types";
import { IInitialState } from "../../store/types";
export const getTodoList = () => async (dispatch: Dispatch<IInitialState>) => {
dispatch({ type: ETodoTypes.TODO_FETCH_LOADING });
try {
const res = await axios.get(`http://jsonplaceholder.typicode.com/todos`);
dispatch({ type: ETodoTypes.TODO_FETCH_SUCCESS, payload: res.data });
} catch (error) {
dispatch({ type: ETodoTypes.TODO_FETCH_ERROR });
}
};
todolist.tsx书写
我们知道它是由一个列表组成,那么我们引入antd中的列表组件,为他生成一个list
import React from "react";
import { connect } from "react-redux";
import { List, Button } from 'antd';
import { getTodoList } from "./service/todoAction";
import { AppState } from "../store";
interface ITodoProps {
state: AppState;
getTodoList: () => void;
}
class TodoList extends React.Component<ITodoProps> {
render() {
console.log(this.props);
const { state } = this.props;
return <div>
<List
size="small"
bordered
loading={state.todo.isLoading}
dataSource={state.todo.todolist}
renderItem={(item) => <List.Item>{item.title}<Button>删除</Button></List.Item>}
/>
</div>;
}
componentDidMount() {
this.props.getTodoList()
}
}
const mapStateToProps = (state: AppState) => ({
state
});
const mapDispatchToProps = (dispatch: any) => ({
getTodoList: () => dispatch(getTodoList())
});
export default connect(mapStateToProps, mapDispatchToProps)(TodoList);
看,他已经可以顺利加载数据了
接下来我们在每一条后面,增加一个删除按钮
在todoAction.ts
中增加如下
export const removeItem = (todos: Array<any>, index: number) => (dispatch: Dispatch<IInitialState>) => {
dispatch({ type: ETodoTypes.TODO_FETCH_LOADING });
try {
todos.splice(index, 1)
dispatch({ type: ETodoTypes.TODO_REMOVE_ITEM, payload: todos });
} catch (error) {
dispatch({ type: ETodoTypes.TODO_FETCH_ERROR });
}
};
todoList
的mapDispatchToProps
中也增加相应的
removeItem: (todos: Array<any>, index: number) => dispatch(removeItem(todos, index))
在按钮中调用该方法即可
todoControl的书写
todoControl
主要是有两个功能,一个是增加一条,一个是刷新列表
他独立于todoList
,属于两个子组件通信,其实我写到这里,我也没有尝试过
让我们来一起试一下
todoControl
中代码如下
import React, { Component } from 'react'
import { connect } from 'react-redux';
import { AppState } from '../store';
import { addItem, refreshTodo } from './service/todoAction';
import { Button } from 'antd';
interface ITodoControlProps {
state: AppState;
refreshTodo: () => void;
addItem: (todos: Array<any>) => void;
}
class TodoControl extends Component<ITodoControlProps>{
render() {
const { addItem, state, refreshTodo } = this.props
return (
<div>
<Button onClick={refreshTodo}>刷新</Button>
<Button onClick={() => addItem(state.todo.todolist)}>随机添加</Button>
</div>
)
}
}
const mapStateToProps = (state: AppState) => ({
state
});
const mapDispatchToProps = (dispatch: any) => ({
addItem: (todos: Array<any>) => dispatch(addItem(todos)),
refreshTodo: () => dispatch(refreshTodo()),
});
export default connect(mapStateToProps, mapDispatchToProps)(TodoControl);
todoAction
export const addItem = (todos: Array<any>) => (dispatch: Dispatch<IInitialState>) => {
dispatch({ type: ETodoTypes.TODO_FETCH_LOADING });
try {
let item = {
userId: Math.random(),
id: Math.random(),
title: `Title:${Math.random()}`,
completed: false
}
todos.unshift(item)
dispatch({ type: ETodoTypes.TODO_ADD_ITEM, payload: todos });
} catch (error) {
dispatch({ type: ETodoTypes.TODO_FETCH_ERROR });
}
};
export const refreshTodo = () => async (dispatch: Dispatch<IInitialState>) => {
dispatch({ type: ETodoTypes.TODO_FETCH_LOADING });
try {
const res = await axios.get(`http://jsonplaceholder.typicode.com/todos`);
dispatch({ type: ETodoTypes.TODO_FETCH_SUCCESS, payload: res.data });
} catch (error) {
dispatch({ type: ETodoTypes.TODO_FETCH_ERROR });
}
};
Great! 完成!