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(
// addDecoratorsLegacy(),//使用装饰器 //需要引入@babel/plugin-proposal-decorators依赖,next ts可以使用 react ts版本无法使用
fixBabelImports("import", { libraryName: 'antd', style: true }),//style为true则表示使用未编译的less样式,这是可以定制主题色了
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 });
//异步action
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;
// action类型
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;//reducer的action接收的类型
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>;//获取合并后的reducers类型
//第一个参数就是组合后的reducers 第二个参数就是默认值 第三个就是异步的thunk那些
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>) => {
// console.log(e.currentTarget.value);
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" />{/* 需要设置name*/}
<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 };
//RouteComponentProps:路由库自带的api的类型定义
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>
{/* 新版的antd用ConfigProvider配合moment使用国际化定义 */}
<ConfigProvider locale={zhCN}>
<App />
</ConfigProvider>
</Router>
</Provider>
);
ReactDOM.render(<Root />, document.getElementById('root') as HTMLElement);
最终重启项目即可 (有什么不足之处可以提出意见)
如果想看案例的大佬则直接点击这里前往github获取代码
原文地址:https://blog.csdn.net/weixin_43902189/article/details/99681548
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。