前言

本教程不用react-script这种工具,用的webpack + eslint(可选) + prettier(可选) + babel,使用编辑器用的vscode。
以下会涉及到ts语法和reduxreact-router-dom的一些技巧,也是入门时学习到的。

准备工作

depend

# babel
yarn add @babel/core @babel/preset-reac @babel/preset-typescript @babel/preset-env -D
# webpack
yarn add webpack webpack-cli webpack-dev-server html-webpack-plugin babel-loader css-loader fork-ts-checker-webpack-plugin -D
# react-hot-reload
yarn add @pmmmwh/react-refresh-webpack-plugin react-refresh type-fest -D
# react 相关
yarn add react react-dom react-redux react-router-dom redux-thunk
# 以上的这些react相关全部装个type,例子
# yarn add @types/react @types/react-dom ... -D
# eslint 可选
yarn add babel-eslint @typescript-eslint/eslint-plugin @typescript-eslint/parser eslint eslint-config-prettier eslint-plugin-prettier eslint-plugin-react-hooks -D

envfile

tsconfig.json

这里我的工程文件都放在./src

{"compilerOptions": {"baseUrl": ".","paths": {"@root/*": ["src/*"]},"outDir": "./dist/","sourceMap": true,"noImplicitAny": true,"lib": ["es6","es7","dom"],"target": "es5","jsx": "react","allowJs": true,"experimentalDecorators": true,"allowSyntheticDefaultImports": true},"include": ["./src/**/*"]
}

.babelrc

{"presets": ["@babel/preset-env","@babel/preset-typescript","@babel/preset-react"]
}

.eslintrc.js

module.exports = {root: true,env: {commonjs: true,es6: true,browser: true,node: true,},parser: '@typescript-eslint/parser',plugins: ['@typescript-eslint', 'prettier'],extends: ['eslint:recommended','plugin:@typescript-eslint/recommended','plugin:react-hooks/recommended','plugin:prettier/recommended','prettier',],parserOptions: {ecmaFeatures: {jsx: true,},},ignorePatterns: ['dist', 'lib'],rules: {'@typescript-eslint/no-var-requires': 0,'@typescript-eslint/no-unused-vars': 0,'prefer-const': 0,'@typescript-eslint/no-explicit-any': 0,'react-hooks/exhaustive-deps': 0,},
}

.prettierrc

{"semi": false,"singleQuote": true
}

webpack.dev.js

const path = require('path')
const HTMLWebpackPlugin = require('html-webpack-plugin')
const ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin')const ReactRefreshWebpackPlugin = require('@pmmmwh/react-refresh-webpack-plugin')module.exports = {entry: './src/index.tsx',output: {filename: 'app.js',path: path.join(__dirname, './dist'),publicPath: '/',},context: path.resolve(__dirname, './src'),devtool: 'cheap-module-source-map',devServer: {hot: true,// enable HMR on the servercompress: true,contentBase: path.resolve(__dirname, './src'),// match the output pathpublicPath: URL,historyApiFallback: true,},mode: 'development',module: {rules: [{test: /\.[tj]sx?$/,exclude: /node_modules/,use: ['babel-loader'],},{test: /\.css$/i,use: ['style-loader',{loader: 'css-loader',options: {modules: {mode: 'global',localIdentName: '[name]__[local]--[hash:base64:5]',},importLoaders: 2,},},],},],},resolve: {alias: {'@root': path.resolve(__dirname, './src'),},extensions: ['.ts', '.tsx', '.js', '.json'],},plugins: [// 用来检测开发中ts语法错误问题new ForkTsCheckerWebpackPlugin({typescript: {configFile: path.resolve(__dirname, './tsconfig.json'),},}),new ReactRefreshWebpackPlugin(),new HTMLWebpackPlugin({template: './src/app.html',filename: 'index.html',}),],
}

基本开发

index.tsx

import * as React from 'react'
import * as ReactDOM from 'react-dom'
import App from '@root/App'ReactDOM.render(<App />, document.getElementById('app'))

App.tsx

import * as React from 'react'
import { Provider } from 'react-redux'
import { BrowserRouter, Route, Switch } from 'react-router-dom'
// 这里redux下面会给写法
import store from './reducers'const App: React.FC = function App(props) {return (<Provider store={store}><BrowserRouter><Switch><Route path="/a1"><div>page a1</div></Route><Route path="/"><div>home</div></Route></Switch></BrowserRouter></Provider>)
}
export default App

redux相关

这里以多个模块组合为例

/reducers/folder.ts

// 定义state
export type FolderDstate = {folders: {name: string}[]isLoading: booleanloaded: boolean
}
let dstate: FolderDstate = {folder: [],isLoading: false,loaded: false,
}// 集合所有action
export type FolderAction =| FolderLoad| FolderUpdatetype FolderLoad = {type: 'folder/load'folders: {name: string}[]
}
type FolderUpdate = {type: 'folder/update'isLoading?: booleanloaded?: boolean
}let folder = (state = dstate, action: FolderAction): FolderDstate => {switch (action.type) {case 'folder/update': {return {...state,isLoading: action.isLoading ?? state.isLoading,loaded: action.loaded ?? state.loaded,}}case 'folder/load': {return {...state,folders: [...action.folders],}}
}
export default folder

这里用的switch是因为vscode会有case提示

并且每块case中的变量都是相对独立于上面定义的type的

/reducers/index.ts

import { combineReducers, createStore, applyMiddleware, compose } from 'redux'
import thunkMiddleware from 'redux-thunk'
import folder, { FolderAction, FolderDstate } from './folder'let rootReducer = combineReducers({folder,
})let store = (function configureStore() {// 这里是添加插件使chrome的redux插件能检测并使用
// 这里window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__会被ts爆出错误,以下会给解决方案const middlewares = [thunkMiddleware]const middlewaresEnhancer = applyMiddleware(...middlewares)const composeEnhancers =window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || composeconst store = createStore(rootReducer,composeEnhancers(middlewaresEnhancer))return store
})()export default store
// 这里放进去所有的模块默认state type
export type StateBase = {folder: FolderDstate//other: otherDstate
}
// 这里放进去所有的action集合,用|连接
export type RootActions = FolderAction /*| otherAction */

redux-connect用法

import * as React from 'react'
import { connect, ConnectedProps } from 'react-redux'
// --- 这里的Dispatch最好用一个ts文件集中管理,这里方便就放一起了 ---
import { RootActions, StateBase } from '@root/reducers'
import { Dispatch } from 'redux'export const loadFolder = (isForce = false) => (dispatch: Dispatch<RootActions>,getState: () => StateBase
): Promise<void> => {const state = getState()if (state.folder.isLoading || (!isForce && state.user.loaded)) returndispatch({ type: 'folder/load', folders: [] })dispatch({ type: 'folder/update', loaded:true  })
}
// -------------// 定义传入参数,ConnectedProps是把connect里的所有方法和变量都打包一起了
type Props = ConnectedProps<typeof connector> & {//自定义参数
}const Comp1: React.FC<Props> = (props) => {React.useEffect(()=>{props.loadFolder()},[])return <div>{`${props.loaded}`}</div>
}const mapStateToProps = (state: StateBase) => {return {loaded: state.folder.loaded,}
}const mapDispatchToProps = {loadFolder
}let connector = connect(mapStateToProps, mapDispatchToProps)export default connector(Comp1)

loadFolder里的dispatch方法提示,都会根据type提示需要的参数

单独带提示的dispatch useDp.ts

import { RootActions } from '@root/reducers'
import { useDispatch } from 'react-redux'export const useDp = (): React.Dispatch<RootActions> =>useDispatch<React.Dispatch<RootActions>>()

效果

关于ts的一些东西

全局变量

./src下随便建个什么的global.d.ts,放一些ts没法检测的全局变量

interface Window {__REDUX_DEVTOOLS_EXTENSION_COMPOSE__: (...any: any) => any
}

将type变成全部可选的新type

export type DeepPartial<T> = {[K in keyof T]?: T[K] extends object ? DeepPartial<T[K]> : T[K]
}
// 这里FolderDstate的所有属性就变成全选了
type n = DeepPartial<FolderDstate>

动态key

如果用了eslint使用object类型他会报错,这样就是动态key了

type dykey = {[key:string]:any
}

end

npx webpack serve --config webpack.dev.js 就ok了

比较全面的typescript + react 开发教程相关推荐

  1. 最全面的Unity游戏开发指南视频教程 第2卷

    最全面的Unity游戏开发指南视频教程 第2卷 流派:电子学习| MP4 |视频:h264,1280×720 |音频:AAC,44.1 KHz 语言:英语+中英文字幕(根据原英文字幕机译更准确)|大小 ...

  2. react开发教程(十)redux结合react

    描述 Redux 和 React 之间没有关系.Redux 可以搭配 React.Angular 甚至纯 JS.但是 Redux 还是比较适合和 React 搭配的,因为 React 允许你以 sta ...

  3. 最全面的Android Studio使用教程【申明:来源于网络】

    最全面的Android Studio使用教程[申明:来源于网络] http://www.admin10000.com/document/5496.html 转载于:https://www.cnblog ...

  4. react开发教程(九)redux基础

    Readux基础 什么是redux? 简单点回答就是,一个管理数据的全局对象,但是它有单一状态树的概念,所谓的单一状态树,就是指"所有的 state都以一个对象树的形式储存在一个单一的 st ...

  5. 史上最全面的python学生管理系统教程(二)

    目录 序言 sqlite使用教程 python sqlite使用教程 数据库构造 学生信息表结构: 教师信息表结构: 课程成绩表结构: 教师添加课程: 学生表连接课程成绩表: 数据库语句了解 sqli ...

  6. 一篇很全面的freemarker 前端web教程

    FreeMarker的模板文件并不比HTML页面复杂多少,FreeMarker模板文件主要由如下4个部分组成:  1,文本:直接输出的部分  2,注释:<#-- ... -->格式部分,不 ...

  7. python中的类装饰器应用场景_这是我见过最全面的Python装饰器教程了!

    装饰器(Decorators)是 Python 的一个重要部分.简单地说:他们是修改其他函数的功能的函数.他们有助于让我们的代码更简短,也更Pythonic(Python范儿).在程序开发中经常使用到 ...

  8. 最全面的WordPress建站教程,零基础30分钟学会建站

    宝塔面板添加WordPress站点 一.建站准备条件 条件1:阿里云服务器一台.原则上有台服务器就好了,不过我一般喜欢用大品牌,稳定和安全. 条件2: 阿里云域名一个.在哪家买的服务器,就用哪家的域名 ...

  9. 最强最全面的Hive SQL开发指南,超四万字全面解析!

    本文整体分为两部分,第一部分是简写,如果能看懂会用,就直接从此部分查,方便快捷,如果不是很理解此SQl的用法,则查看第二部分,是详细说明,当然第二部分语句也会更全一些! 第一部分: hive模糊搜索表 ...

最新文章

  1. 计算机本科学位有用吗_我应该回到学校获得计算机科学学位吗?
  2. Web前端开发人员和设计师必读文章推荐【系列七】
  3. 委托与事件代码详解与(Object sender,EventArgs e)详解
  4. 《基于张量网络的机器学习入门》学习笔记6
  5. Jerry的反省:程序员不要轻易说出“这个功能技术上无法实现“
  6. java dll 乱码_java调用c++ dll出现中文乱码 | 学步园
  7. [html] 如何设置打印尺寸?
  8. python import如何使用_python之import引用
  9. 「深入浅出」主流前端框架更新批处理方式
  10. 草稿 图片盒子定时器模式窗口
  11. 【clickhouse】ClickHouse官方中文文档 阅读笔记
  12. 又来?软件测试之接口自动化面试题汇总
  13. 小程序用php的优势,小程序的特点及优势?
  14. JS面向对象的程序设计(二)
  15. SQLServer之创建Transact-SQL DDL触发器
  16. 此语言无法安装在此计算机上win10,如何解决Win10换成无法安装英文语言包的问题...
  17. steam服务器连接不稳定WIN10,小编操作win10系统steam连接不稳的解决步骤
  18. 可视化图布局算法浅析
  19. 浏览器屏蔽百度推广广告
  20. 【机器学习】07. 决策树模型DecisionTreeClassifier(代码注释,思路推导)

热门文章

  1. 微信开发平台账号权限申请过程
  2. itextpdf给pdf添加水印
  3. swaggerUI页面没有显示api
  4. 通过这一篇理解关于网络的一些问题
  5. 校园无线网络规划与设计
  6. 基于springboot在线答疑系统
  7. android ble 蓝牙绑定流程,android BLE蓝牙开发
  8. Linux用命令安装音乐软件,在Ubuntu 18.04系统中使用命令安装Qmmp音乐播放器的方法...
  9. android afw 权限,如何从adb shell命令启动AFW徽章应用程序?
  10. MP3基本知识及构成