2018年的六一儿童节已到,特此一篇来献给小盆友们。此处应该有掌声....
写在前面: 首先,什么是TypeScript?
官方原话:TypeScript is a typed superset of JavaScript that complies to plain JavaScript. Any host. Any OS. Open source. TypeScript是JavaScript类型的超集(强类型版本),它可以编译成纯的JavaScript,它可以再任何浏览器,任何计算机和任何操作系统上运行,并且开源。
嗯,是的,你可以理解为TypeScript硬是把JavaScript(弱类型语言)"掰弯"了,变成强类型语言;强类语言的优势在于静态类型的检查,TypeScript虽然是强类型的语言,但是如果对象被声明为any类型,就会忽略所有的类型检查。这种灵活的结构保证了它整体有强类语言检查优势的同时,在一些细节问题上保持了弱类型的灵活。
1.为了能够快速搭建应用,我们将使用create-react-app官方脚手架为基础进行扩展。
创建一个项目(TypeScript版本)
npx create-react-app 项目名称 --scripts-version=react-scripts-ts
2.安装所需依赖包
yarn add history @types/history react-router-dom @types/react-router-dom react-router-redux @types/react-router-redux redux-actions @types/redux-actions redux-thunk @types/redux-thunk redux --D
*注意:
(1).redux 已经包含TypeScript包
(2).redux-thunk:2.20目前会报语法错误,解决方法:
修改node_modules/redux-thunk/index.d.ts
import { Middleware, Dispatch, Action, AnyAction } from 'redux';
export type ThunkAction<R, S, A extends Action = AnyAction, E = {}> = {
(dispatch: Dispatch<A, S>, getState: () => S, extraArgument: E): R
}
declare module 'redux' {
export interface Dispatch<A extends Action = AnyAction, S = {}> {
<R, E>(thunk: ThunkAction<R, S, A, E>): R
}
}
declare const thunk: Middleware & {
withExtraArgument(extraArgument: any): Middleware;
};
export default thunk;
3.开始编码
(1) 新建一个models.ts
// store中初始状态的接口声明
export interface ITodoModel {
id?: number;
text: string;
completed: boolean;
}
(2) 新建一个types.ts
// action 的唯一标识符
export const ADD_TODO = 'ADD_TODO';
(3) 新建一个anctions.ts
/**
*** 因为store中状态是只读的(可以使用store.getState()来获取整个store的状态)
*** 要改变它里面的状态只能分发一个action去改变其属性
**/
// createAction 让你可以轻松创建一个action
import {createAction} from 'redux-actions';
import {ITodoModel} from './models';
import {ADD_TODO} from './types';
const addTodo = createAction<ITodoModel, string>(
ADD_TODO,
(text: string) => ({text, completed: false})
);
export {
addTodo
}
(4) 新建一个reducers.ts
import {handleActions} from 'redux-actions';
import {ADD_TODO} from './types';
import {ITodoModel} from './models'
// 初始的状态,就像react中组件内的初始状态,只不过这个是全局的。
const initialState: ITodoModel = {
completed: true,
id: 1,
text: 'Use Redux',
};
export const todoReducer = handleActions<ITodoModel>({
[ADD_TODO]: (state: any, action: any) => {
console.log('reducer->state:', state);
console.log('reducer->action:', action);
return {completed: true, text: action.payload.text, id: 2};
},
}, initialState);
(5) 开始组建store
1. store->initState.ts
import {ITodoModel} from '../containers/home/modules/models';
export interface IRootState {
todo: ITodoModel;
}
2. store->reducer.ts
import {combineReducers} from 'redux';
import {todoReducer} from '../containers/home/modules/reducers';
// 把前面的reducers combine 起来
const rootReducer = combineReducers({
todo: todoReducer as any
});
export default rootReducer;
3. store->reducer.ts
import {Store, createStore, applyMiddleware} from 'redux';
import {routerMiddleware} from 'react-router-redux';
import thunkMiddleware from 'redux-thunk';
import rootReducer from './reducer';
import {IRootState} from './initState';
import {History} from 'history';
export function configureStore(history: History, initialState?: IRootState): Store<IRootState> {
// store 中间件,根据个人需求添加
const middleware = applyMiddleware(
thunkMiddleware,
routerMiddleware(history));
return createStore(
rootReducer as any,
initialState as any,
middleware
) as Store<IRootState>;
}
(6) 修改入口文件index.tsx
import * as React from 'react';
import * as ReactDOM from 'react-dom';
import {Provider} from 'react-redux';
import registerServiceWorker from './registerServiceWorker';
import Routers from './containers/Routers';
import createHistory from 'history/createBrowserHistory'
import {configureStore} from './store';
const history = createHistory();
const store = configureStore(history);
ReactDOM.render(
<Provider store={store}>
<Routers/>
</Provider>
,
document.getElementById('root') as HTMLElement
);
registerServiceWorker();
(7) 如何使用?
import * as React from 'react';
import {Dispatch} from 'redux';
import {connect} from 'react-redux';
import {addTodo} from './containers/home/modules/anctions';
import {Button} from 'antd';
import './App.less';
interface IAppProps {
addTodo?: any;
todos?: any;
}
class App extends React.Component<IAppProps> {
constructor(props: any) {
super(props);
}
// 组件内分发action,改变store中的属性值
public change = () => {
const myName = '我叫二白';
this.props.addTodo(myName)
};
// 把store绑定在视图层上
public render() {
console.log(this.props);
return (
<div className='App'>
<div>{this.props.todos.todo.text}</div>
<Button onClick={() => this.change()}>redux点击一下</Button>
</div>
);
}
}
// mapStateToProps(state, ownProps) 方法允许我们将store中的数据作为props绑定到组件中,
只要store更新了就会调用mapStateToProps方法,
mapStateToProps返回的结果必须是object对象,该对象中的值将会更新到组件中;
const mapStateToProps = (state: any) => ({
todos: state
});
// mapDispatchToProps(dispatch, [ownProps]) 第二个参数允许我们将action作为props绑定到组件中,
mapDispatchToProps希望你返回包含对应action的object对象;
const mapDispatchToProps = (dispatch: Dispatch<any>) => {
return {
addTodo: (payload: string) => dispatch(addTodo(payload)),
}
};
export default connect(mapStateToProps, mapDispatchToProps)(App);