安装
用TypeScript创建一个React应用
create-react-app appname --typescript
查看package.json文件中React的版本是否是最新版本,因为TypeScript可以使用最新版本的React和JavaScript,本篇文章中,最新版本的React是v16.7.0,所以如果这不是自动安装的,那么让我们更新它:
npm install react@16.7.0-alpha.0 npm install react-dom@16.7.0-alpha.0
添加Redux依赖
npm install redux react-redux
还需要react-redux的TypeScript类型
npm install --save-dev @types/react-redux
最后,让我们添加axios,redux-thunk和相应的thunk类型
npm install axios npm install redux-thunk npm install --save-dev @types/redux-thunk
最终的工程结构如下
设置Reducer
Reducers指定应用程序的状态如何响应发送到存储的操作而更改。
[characterReducer.ts]
// 导入Reducer依赖
import { Reducer } from 'redux';
import {
CharacterActions,
CharacterActionTypes,
} from '../actions/CharacterActions';
// 定义Character类型
export interface ICharacter {
name: string;
height: string;
mass: string;
hair_color: string;
skin_color: string;
eye_color: string;
birth_year: string;
gender: string;
homeworld: string;
films: string[];
species: string[];
vehicles: string[];
starships: string[];
created: string;
edited: string;
url: string;
}
// 定义Character的State
export interface ICharacterState {
readonly characters: ICharacter[];
}
// 定义初始化state
const initialCharacterState: ICharacterState = {
characters: [],
};
export const characterReducer: Reducer<ICharacterState, CharacterActions> = (
state = initialCharacterState,
action
) => {
switch (action.type) {
case CharacterActionTypes.GET_ALL: {
return {
...state,
characters: action.characters,
};
}
default:
return state;
}
};
我们将使用Swapi API通过我们的操作获取数据。 ICharacter接口正在为我们从API返回的数据建模。
设置Action
[CharacterActions.ts]
// 导入redux类型
import { ActionCreator, Dispatch } from 'redux';
import { ThunkAction } from 'redux-thunk';
import axios from 'axios';
// 导入Character类型
import { ICharacter, ICharacterState } from '../reducers/characterReducer';
// 创建Action常量
export enum CharacterActionTypes {
GET_ALL = 'GET_ALL',
}
// 获取所有操作类型的接口
export interface ICharacterGetAllAction {
type: CharacterActionTypes.GET_ALL;
characters: ICharacter[];
}
/*
将动作类型与联合组合(我们假设还有更多)
example: export type CharacterActions = IGetAllAction | IGetOneAction ...
*/
export type CharacterActions = ICharacterGetAllAction;
/* 获取所有Action
<Promise<Return Type>, State Interface, Type of Param, Type of Action>
*/
export const getAllCharacters: ActionCreator<
ThunkAction<Promise<any>, ICharacterState, null, ICharacterGetAllAction>
> = () => {
return async (dispatch: Dispatch) => {
try {
const response = await axios.get('https://swapi.co/api/people/');
dispatch({
characters: response.data.results,
type: CharacterActionTypes.GET_ALL,
});
} catch (err) {
console.error(err);
}
};
};
设置Store
在前面的部分中,我们定义了表示“发生了什么”的事实的Action以及根据这些动作更新状态的Reducers。
Store将它们组合在一起的对象
[Store.tsx]
import { applyMiddleware, combineReducers, createStore, Store } from 'redux';
import thunk from 'redux-thunk';
// 导入reducers和state类型
import {
characterReducer,
ICharacterState,
} from '../reducers/characterReducer';
// 创建一个应用状态接口
export interface IAppState {
characterState: ICharacterState;
}
// 创建root reducer
const rootReducer = combineReducers<IAppState>({
characterState: characterReducer,
});
// 创建一个类型为“IAppState”的配置存储函数
export default function configureStore(): Store<IAppState, any> {
const store = createStore(rootReducer, undefined, applyMiddleware(thunk));
return store;
}
设置Index
[index.tsx]
import * as React from 'react';
import * as ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import { Store } from 'redux';
import configureStore, { IAppState } from './store/Store';
import { getAllCharacters } from './actions/CharacterActions';
import './index.css';
import App from './components/App';
interface IProps {
store: Store<IAppState>;
}
const Root: React.SFC<IProps> = props => {
return (
<Provider store={props.store}>
<App />
</Provider>
);
};
// 生成store
const store = configureStore();
store.dispatch(getAllCharacters());
// 渲染App
ReactDOM.render(<Root store={store} />, document.getElementById(
'root'
) as HTMLElement);
最后,Components/Containers
Components:React组件是小的,可重用的代码片段,它们返回要呈现给页面的React元素。
Containers:反应与事物如何工作和了解Redux有关的组件。
[App.tsx (Component)]
import * as React from 'react';
import '../App.css';
import CharacterList from '../containers/CharacterList';
const App: React.SFC<{}> = () => {
return (
<>
<h1>The Force Awakens</h1>
<CharacterList />
</>
);
};
export default App;
[CharacterList.tsx (Container)]
import * as React from 'react';
import { connect } from 'react-redux';
import { IAppState } from '../store/Store';
import { ICharacter } from '../reducers/characterReducer';
// 创建容器接口
interface IProps {
characters: ICharacter[];
}
class CharacterList extends React.Component<IProps> {
public render() {
const { characters } = this.props;
return (
<div className="name-container">
{characters &&
characters.map(character => {
return (
<span key={character.name} className="name">
{character.name}
</span>
);
})}
</div>
);
}
}
const mapStateToProps = (store: IAppState) => {
return {
characters: store.characterState.characters,
};
};
export default connect(mapStateToProps)(CharacterList);
运行
npm start
