优秀的编程知识分享平台

网站首页 > 技术文章 正文

在React中使用Redux和TypeScript(react-redux provider)

nanyue 2024-07-25 06:01:02 技术文章 16 ℃

安装

用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

Tags:

最近发表
标签列表