###配合TypeScript
第一种方式:创建项目的时候直接配置好TypeScript
.
npx create-react-app my-app --typescript
#or
yarn create react-app my-app --typescript
第二种方式:为现有的React项目添加TypeScript
npm install --save typescript @types/node @types/react @types/react-dom @types/jest
# or
yarn add typescript @types/node @types/react @types/react-dom @types/jest
安装完成后,项目根目录下新建 tsconfig.json文件
{
"compilerOptions": { // 编译选项
"target": "es2016", // 配置编译目标代码的版本标准
"module": "commonjs", // 配置编译目标使用的模块化标准
"lib": ["es2016"]
}
}
ts和js分开
开发过程中我们肯定希望源代码和编译后的代码分开,加入以下两个配置选项
include : 需要编译的文件目录
outDir: 编译后的文件目录
{
"compilerOptions": { // 编译选项
"target": "es2016", // 配置编译目标代码的版本标准
"module": "commonjs", // 配置编译目标使用的模块化标准
"lib": ["es2016","dom"], // 配置环境
"outDir": "./dist"
},
"include": ["./src"]
}
###Visual Studio Code配置React开发环境
## Visual Studio Code配置React开发环境
### React集成VSCode测试
第一步:
首先安装:[`Debugger for Chrome`](https://marketplace.visualstudio.com/items?itemName=msjsdiag.debugger-for-chrome)插件。
第二步: 项目根目录下创建 `.vscode`文件夹。
第三步:创建`launch.json`文件
文件内容:
```json
{
"version": "0.2.0",
"configurations": [
{
"name": "Chrome",
"type": "chrome",
"request": "launch",
"url": "http://localhost:3000",
"webRoot": "${workspaceFolder}/src",
"sourceMapPathOverrides": {
"webpack:///src/*": "${webRoot}/*"
}
}
]
}
##第11步:配置路由,登录
//安装 react-loadable 用来实现按需加载显示页面
npm i react-loadable -S
npm i react-router-dom -S
新建路由文件夹routes
src/routes/index.js
src/routes/initDataRoute.js
// src/routes/index.js
import React from 'react';
import { HashRouter, Switch, Route } from 'react-router-dom';
import { initRoutes, initRouteConfig } from './initDataRoute';
import { Home, ErrorView, } from '../views/index'
import App from '../App';
// 根据权限渲染的菜单数据
let childRoutes = initRoutes;
// 根据权限渲染的路由数据
let routeConfig = initRouteConfig;
class Routes extends React.PureComponent{
constructor(props){
super(props);
this.state = {
}
}
componentDidMount() {
}
render(){
return( <HashRouter>
<>
<App>
<Switch>
<Route path="/" component={Home} exact key="firstPage"/>
<Route path='/404' component={ErrorView} exact key='errorPage'/>
{
routeConfig.length > 0 && routeConfig.map((item, index) => {
return (
<Route path={item.path} component={item.component} key={`route${index}`}/>)
})
}
{
routeConfig.length > 0 && <Route component={ErrorView} key="error"/>
}
</Switch>
</App>
</>
</HashRouter> )
}
}
export default Routes
export {childRoutes, routeConfig};
// src/routes/initDataRoute.js
/**
* 配置懒加载路由
*/
import { Home, Menu1, Menu2, Menu3, ErrorView, Login, Register } from '../views'
//通过组件配置一级菜单
const initRoutes = [{
path: '/home',
component: Home,
title: '首页'
}, {
path: '/menu1',
component: Menu1,
title: '菜单一'
}, {
path: '/menu2',
component: Menu2,
title: '菜单二'
}, {
path: '/menu3/detail/:id',
component: Menu3,
title: '菜单三'
},
];
// 所有的路由配置
const initRouteConfig = [
...initRoutes,
{
path: '/register',//测试页使用,实际是登录里的子组件
component: Register,
title: '注册'
}, {
path: '/error',
component: ErrorView,
title: '错误页'
}, {
path: '/login',
component: Login,
title: '登录'
},
];
export { initRoutes, initRouteConfig }
在src下新建文件
-
src
-
components
- Header
- index.js
- index.scss
- Header
-
routes
- index.js
- initDataRoute.js
-
views
-
ErrorView
- index.js
- index.scss
-
Home
- index.js
- index.scss
-
Login
- Register
- index.js
- index.scss
- index.js
- index.scss
- Register
-
Menu1
- index.js
- index.scss
-
Menu2
- index.js
- index.scss
-
Menu3
- index.js
- index.scss
-
index.js------------views/index.js 导出懒加载路由
-
-
// views/index.js
/**
* 配置懒加载路由
*/
import Loadable from 'react-loadable';
const Loading = () => null; //加载时不显示loading
const Home = Loadable({
loader: () => import('./Home'), //按需加载 点击时只加载一个页面
loading: Loading,
});
const Menu1 = Loadable({
loader: () => import('./Menu1'),
loading: Loading,
});
const Menu2 = Loadable({
loader: () => import('./Menu2'),
loading: Loading,
});
const Menu3 = Loadable({
loader: () => import('./Menu3'),
loading: Loading,
});
const ErrorView = Loadable({
loader: () => import('./ErrorView'),
loading: Loading,
});
const Login = Loadable({
loader: () => import('./Login'),
loading: Loading,
});
const Register = Loadable({
loader: () => import('./Login/Register'),
loading: Loading,
});
export {
Home,
Menu1,
Menu2,
Menu3,
ErrorView,
Login,
Register
}//将页面导出
// src/index.js
import 'babel-polyfill';
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import Routes from './routes/index';
import * as serviceWorker from './serviceWorker';
ReactDOM.render( <Routes /> , document.getElementById('root'));
// If you want your app to work offline and load faster, you can change
// unregister() to register() below. Note this comes with some pitfalls.
// Learn more about service workers: http://bit.ly/CRA-PWA
serviceWorker.unregister();
// src/App.js
import React, { PureComponent } from 'react';
import './App.scss';
import './assets/css/common.scss'
import Header from './components/Header'
import { ConfigProvider } from 'antd'
import { withRouter } from 'react-router-dom';
import zhCN from 'antd/es/locale/zh_CN';
import moment from 'moment';
import 'moment/locale/zh-cn';
moment.locale('zh-cn');
class App extends PureComponent {
render() {
const {location, children} = this.props;
return (
<ConfigProvider locale={zhCN}>
<div className="app-wrap" key={this.props.location.key}>
{
location.pathname && location.pathname !== '/404' ?
<Header {...this.props}/>
: null
}
<div className="app-main">
{children}
</div>
</div>
</ConfigProvider>
);
}
}
export default withRouter(App);
// src/components/Header/index.js
/**
* 头部组件
*/
import React, { Component } from 'react';
import { Menu, Icon } from 'antd';
import { childRoutes } from "../../routes";
// const { SubMenu } = Menu;
class Header extends Component {
constructor(props) {
super(props);
this.state = {
current: '',
}
}
componentDidMount() {
}
handleMenuClick = (e) => {
this.setState({
crurent: e.key
},() => {
this.props.history.push(e.key)
})
}
render() {
const menuList = childRoutes.length > 0 && childRoutes.map((item,index) => {
return (
<Menu.Item
key={item.path}>
<Icon type="mail" />
{item.title}
</Menu.Item>
)
})
return (
<>
<Menu
onClick={this.handleMenuClick}
selectedKeys={[this.state.current]}
mode="horizontal">
{menuList}
</Menu>
</>
);
}
}
export default Header;
目前的项目运行效果如下:
##第12步:配置redux
npm install redux react-redux --save
or
yarn add redux react-redux
// 这个版本先不安装
npm install redux-saga --save
新建需要的文件夹
在 src
目录下新建 actions
、reducers
、constants
文件夹,
actions
存放分发的 action
函数;
reducer
存放公用的 reducer
;
constants
存放分发 action
的 type
常量。
- src
- store
- index.js
- actions
- index.js
- constants
- index.js
- reducer
- index.js
- store
在 store
中创建 index.js
,用来组合单个的 reducer
,输出根 state
import { combineReducers } from 'redux'
export default combineReducers({})
- 修改
webpack
文件来设置别名
alias: {
styles: paths.appStyles,
routes: paths.appRoutes,
components: paths.appComponents,
actions: paths.appActions,
constants: paths.appConstants,
reducers: paths.appReducers,
...
// 添加 redux-thunk 异步中间件
npm install redux-thunk --save
修改 routes
文件夹下的 index.js
...
import { Provider } from 'react-redux'
import { createStore, applyMiddleware, compose } from 'redux'
import thunkMiddleware from 'redux-thunk'
import rootReducer from 'reducers'
...
const store = createStore(
rootReducer,
compose(applyMiddleware(thunkMiddleware)),
)
const App = () => (
<Provider store={store}>
<Routes />
</Provider>
)
现在你可以编写你自己的 action
,reducer
了。
在项目中安装 redux-devtools-extension 插件
npm i redux-devtools-extension -D
配合浏览器安装辅助工具 Redux DevTools
Chrome浏览器安装 Redux DevTools
扩展程序,修改 routes
中的 index.js
let composeEnhancers = compose
if (process.env.NODE_ENV === 'development') {
composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose; // eslint-disable-line
}
const store = createStore(
rootReducer,
composeEnhancers(applyMiddleware(thunkMiddleware)),
)
在浏览器界面打开 Redux DevTools
就能看见以下效果
编写middleware
如果需要自定义的 middleware
,很简单,这个 middleware
只接收一个 action
,执行后也需要返回一个 action
;如果需要执行下一步,调用 next(action)
即可。
- 日志的中间件
const logger = store => next => (action) => {
console.log('dispatching', action);
const result = next(action);
console.log('next state', store.getState());
return result;
};
修改 routes
文件夹下的 index.js
,将该日志中间件加上
const store = createStore(
rootReducer,
composeEnhancers(applyMiddleware(thunkMiddleware, logger)),
)
##第13步:
根据是否登录,设置路由
//
##中途遇到的问题
- 问题一:安装插件时如果使用npm就一直是npm,如果使用yarn就继续使用,不能一会使用npm,一会使用yarn,要不就得把node_modules删除,重新安装
未完,待续…
【第一部分】create-react-app 技术栈:react+react-router+redux+axios+es6+webpack
【第二部分】create-react-app 技术栈:react+react-router+redux+axios+es6+webpack
【第三部分】create-react-app 技术栈:react+react-router+redux+axios+es6+webpack