react脚手架typescript版本整合redux、antd按需加载的简单使用(如有侵权,请联系我)
1.下载create-react-app
cnpm i create-react-app -g //全局下载react脚手架,mac用户加上sudo
2.创建react项目(注意:进入启动测试一下项目是否能正常运行)
create-react-app ts-react-study --typescript //--typescript创建脚手架默认引入typescript
3.引入antd,配置按需加载(antd官方有介绍,可以去官方api查看,这里就不用贴了,相信到这里的都是大佬,也可以继续看下去) antdAPI官网链接
cnpm i antd --save //antd就是typescript写的,不需要引入@types/antd这样的依赖
4.引入react-app-rewired、babel-plugin-import、customize-cra依赖配置按需加载
cnpm i react-app-rewired babel-plugin-import customize-cra --save
5.创建一个config-overrides.js文件在根目录下
config-overrides.js文件代码如下
const { override, fixBabelImports, addLessLoader } = require ( "customize-cra" ) ;
module. exports = override (
fixBabelImports ( "import" , { libraryName: 'antd' , style: true } ) ,
addLessLoader ( {
javascriptEnabled: true ,
modifyVars: { '@primary-color' : 'red' }
} )
) ;
6.这时候重新启动会报错,这时候我们还需要less和less-loader,这样就不会报错了
cnpm i less less-loader --save
7.修改package.json文件(把scripts下面的start、test、build替换如下代码)
"scripts" : {
"start" : "react-app-rewired start" ,
"build" : "react-app-rewired build" ,
"test" : "react-app-rewired test" ,
"eject" : "react-scripts eject" ,
"client" : "serve build"
}
重新启动项目 引入antd测试一下样式是否自动导入(修改index.tsx文件)
import React from 'react' ;
import ReactDOM from 'react-dom' ;
import { Button} from 'antd' ;
const Root: React. FC = ( ) => (
< Button> 按钮< / Button>
) ;
ReactDOM. render ( < Root / > , document. getElementById ( 'root' ) as HTMLElement) ;
8.如需要使用scss的大佬,可以直接引入,react脚手架内部有对应的配置
cnpm i sass sass-loader node-sass -D
然后创建一个scss文件测试一下样式是否生效
9.引入react-router-dom路由
cnpm i react-router-dom @types/react-router-dom --save
10.引入redux、react-redux、react-thunk(重点使用)
cnpm i redux react-redux react-thunk @types/react-redux @types/react-thunk -D
11.制作一个简单的计数器案例
11.1创建store目录在src下面
11.2创建actions.ts文件
import { INCREMENT_COUNTER , DECREMENT_COUNTER , INCREMENT_ACTION_TYPE , DECREMENT_ACTION_TYPE } from './types' ;
import { Dispatch } from 'redux' ;
const incrementCount = ( number: number) : INCREMENT_ACTION_TYPE => ( { type: INCREMENT_COUNTER , number } ) ;
export const asyncIncrementCount = ( number: number) => ( dispatch: Dispatch< INCREMENT_ACTION_TYPE > ) => {
setTimeout ( ( ) => dispatch ( incrementCount ( number) ) , 1000 ) ;
}
export const decrementCount = ( number: number) : DECREMENT_ACTION_TYPE => ( { type: DECREMENT_COUNTER , number } ) ;
11.3创建reducers.ts文件
import { ACTION_TYPE , INCREMENT_COUNTER , DECREMENT_COUNTER } from "./types" ;
interface CountState {
count: number
}
export const initialState: CountState = {
count: 0
}
export function countReducer ( state = initialState, action: ACTION_TYPE ) : CountState {
switch ( action. type) {
case INCREMENT_COUNTER :
return { ... state, count: state. count + action. number } ;
case DECREMENT_COUNTER :
return { ... state, count: state. count - action. number } ;
default :
return state;
}
}
11.4创建types.ts文件
export const INCREMENT_COUNTER = "INCREMENT_COUNTER" ;
export type INCREMENT_COUNTER = typeof INCREMENT_COUNTER ;
export const DECREMENT_COUNTER = "DECREMENT_COUNTER" ;
export type DECREMENT_COUNTER = typeof DECREMENT_COUNTER ;
export interface INCREMENT_ACTION_TYPE {
type: INCREMENT_COUNTER ;
number: number;
}
export interface DECREMENT_ACTION_TYPE {
type: DECREMENT_COUNTER ;
number: number;
}
export type ACTION_TYPE = INCREMENT_ACTION_TYPE | DECREMENT_ACTION_TYPE ;
11.5创建index.ts文件
import { createStore, combineReducers, applyMiddleware } from "redux" ;
import thunk from 'redux-thunk' ;
import { countReducer, initialState } from "./reducers" ;
const reducers = combineReducers ( {
countReducer
} ) ;
export type reducerType = ReturnType< typeof reducers> ;
export default createStore ( reducers, {
countReducer: initialState
} , applyMiddleware ( thunk) ) ;
11.6创建hello.tsx在component目录下
import React, { Component } from 'react' ;
import { Button, Input } from 'antd' ;
interface State {
name: string,
value: string,
[ name: string] : number | string
}
interface Props {
title: string;
content? : string;
handleMsg: Function;
}
export default class Hello extends Component < Props, State> {
public constructor ( props: Props) {
super ( props) ;
}
public readonly state = {
name: "Hello" ,
value: ""
}
private handleClick = ( ) => {
const { handleMsg } = this . props;
const { value } = this . state;
if ( ! value) return ;
this . setState ( { name: value } ) ;
handleMsg ( value) ;
}
private handleChange = ( e: React. FormEvent< HTMLInputElement> ) => {
const { name, value } = e. currentTarget;
this . setState ( { [ name] : value } ) ;
}
public render ( ) {
const { title } = this . props;
const { name, value } = this . state;
return (
< >
< h2> { title} < / h2>
< p> { name} < / p>
< p> value: { ' ' + value} < / p>
< Input onChange= { this . handleChange} value= { value} name= "value" / > { }
< Button onClick= { this . handleClick} > 改变name< / Button>
< / >
) ;
}
}
11.7创建pages/counter.tsx文件
import React, { Component } from 'react' ;
import { Button } from 'antd' ;
import { connect } from 'react-redux' ;
import { RouteComponentProps } from 'react-router-dom' ;
import { reducerType } from '../store' ;
import { asyncIncrementCount, decrementCount } from '../store/actions' ;
interface CounterProps {
count: number;
asyncIncrementCount: Function;
decrementCount: Function;
}
const mapStateToProps = ( state: reducerType) => ( { count: state. countReducer. count } ) ;
const mapDispatchToProps = { asyncIncrementCount, decrementCount } ;
class Counter extends Component < RouteComponentProps & CounterProps, { } > {
private increment = ( ) => {
const { asyncIncrementCount } = this . props;
asyncIncrementCount ( 2 ) ;
}
private decrement = ( ) => {
const { decrementCount } = this . props;
decrementCount ( 2 ) ;
}
public render ( ) {
const { count } = this . props;
return (
< div>
< p> count:{ count} < / p>
< Button onClick= { this . increment} > 按钮+ 2 < / Button>
< Button onClick= { this . decrement} > 按钮- 2 < / Button>
< / div>
) ;
}
}
export default connect ( mapStateToProps, mapDispatchToProps) ( Counter) ;
11.8修改App.tsx文件
import React, { Component } from 'react' ;
import { Switch, Route, Redirect, NavLink } from 'react-router-dom' ;
import Hello from './component/hello' ;
import Counter from './pages/counter' ;
interface IState {
message: string
}
class App extends Component < { } , IState> {
public readonly state = {
message: ""
}
public handleMsg = ( message: string) => {
this . setState ( { message } ) ;
}
public render ( ) {
const { message } = this . state;
return (
< >
< h1> { message} < / h1>
< Hello title= "Hello Typescript" handleMsg= { this . handleMsg} / >
< NavLink to= "/counter" activeClassName= "active" > 计数< / NavLink>
< Switch>
< Route path= "/counter" component= { Counter} / >
< Redirect to= "/counter" / >
< / Switch>
< / >
) ;
}
}
export default App;
11.9最后修改index.tsx文件
import React from 'react' ;
import ReactDOM from 'react-dom' ;
import { BrowserRouter as Router } from 'react-router-dom' ;
import { Provider } from 'react-redux' ;
import { ConfigProvider} from 'antd' ;
import store from './store' ;
import App from './App' ;
import zhCN from 'antd/es/locale/zh_CN' ;
import moment from 'moment' ;
import 'moment/locale/zh-cn' ;
moment. locale ( 'en' ) ;
const Root: React. FC = ( ) => (
< Provider store= { store} >
< Router>
{ }
< ConfigProvider locale= { zhCN} >
< App / >
< / ConfigProvider>
< / Router>
< / Provider>
) ;
ReactDOM. render ( < Root / > , document. getElementById ( 'root' ) as HTMLElement) ;
最终重启项目即可 (有什么不足之处可以提出意见)