安装
用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