###配合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刪除,重新安裝
未完,待續…
[百度][http://www.baidu.com]