接着上一篇react+webpack4搭建前端項目(一)咱們正式進入react
全家桶技術篇章,若是對於項目不清楚或者在下面有什麼疑惑,建議先看一下上一篇文章熟悉一下項目由來css
react-router-dom
管理路由,這裏使用react-router4.x之後的版本,請注意,和3.x的使用仍是有很大的區別npm install -S react-router-dom
複製代碼
咱們爲何使用react-router-dom
呢?html
先簡單說下各自的功能: react-router
: 實現了路由的核心功能 react-router-dom
: 基於react-router
,加入了在瀏覽器運行環境下的一些功能,例如:Link
組件,會渲染一個a
標籤,BrowserRouter
和HashRouter
組件。顯而易見react-router-dom
功能更豐富,因此選擇react-router-dom
代替react-router
前端
下面接着上一篇文章的項目,咱們對項目進行改造: 新建blog,resume,user頁面,以下java
blog,resume,user,home
(上篇文章已完成)組件
此處刪除home/index.less
,修改home/index.js
內容:node
import React from 'react'
export default class HomeIndex extends React.Component {
render(){
return (
<div>
<p>HomeIndex</p>
</div>
)
}
}
複製代碼
blog/index.js
react
import React from 'react'
export default class BlogIndex extends React.Component {
render(){
return (
<div>
<p>BlogIndex</p>
</div>
)
}
}
複製代碼
resume/index.js
webpack
import React from 'react'
export default class ResumeIndex extends React.Component {
render(){
return (
<div>
<p>ResumeIndex</p>
</div>
)
}
}
複製代碼
user/index.js
ios
import React from 'react'
export default class UserIndex extends React.Component {
render(){
return (
<div>
<p>UserIndex</p>
</div>
)
}
}
複製代碼
以上這些組件是最簡單的組件git
新建src/router.js
github
import React from "react"
import { Route,BrowserRouter,Link,Switch } from "react-router-dom"
import HomeIndex from "./home"
import BlogIndex from "./blog"
import ResumeIndex from "./resume"
import UserIndex from "./user"
class AppRouter extends React.Component {
render(){
return (
<BrowserRouter>
<ul>
<li><Link to="/home">home</Link></li>
<li><Link to="/blog">blog</Link></li>
<li><Link to="/resume">resume</Link></li>
<li><Link to="/user">user</Link></li>
</ul>
<div>
{/* Switch只顯示一個組件。加exact表示精確匹配/。若是不加exact,/xxx也會匹配/。 */}
<Switch>
{/* exact */}
<Route path="/home" component={HomeIndex} />
<Route exact path="/blog" component={BlogIndex}/>
<Route exact path="/resume" component={ResumeIndex}/>
<Route exact path="/user" component={UserIndex}/>
</Switch>
</div>
</BrowserRouter>
)
}
}
export default AppRouter;
複製代碼
這裏使用react-router-dom
的history模式,簡單寫了一個導航,點擊每一個導航,跳轉到相應的頁面。運行npm run dev
,打開http:localhost:8081
,效果如圖
到此react-router-dom
基本使用已經完成。
由於咱們這裏是配合項目使用,詳細的react-router-dom
不過多講解,若是想學習更多基本用法,請查看官方文檔。在後邊隨着項目的複雜,後邊咱們還會說一下嵌套路由,頁面之間的跳轉等等使用方法。
最後咱們須要清除頁面,標籤的默認樣式。代碼能夠去網上找一份,網上隨處可見。 而後在項目根目錄新建static/css/reset.min.css,在index.html模板引入
<link rel="stylesheet" href="/static/css/reset.min.css">
複製代碼
從新運行,你會發現找不到/static/css/reset.min.css
。由於這裏只是在index.html
中引入了文件,可是並無在webpack
中處理靜態文件,咱們須要把static
目錄的內容經過webpack
插架 編譯構建到包裏;此處須要用到copy-webpack-plugin
npm install -D copy-webpack-plugin
複製代碼
在build/webpack.base.config.js`中添加公用的插件plugins,
plugins:[
new CopyWebpackPlugin([
{
from: utils.resolve('../static'), // 從哪一個目錄copy
to: "static", // copy到那個目錄
ignore: ['.*']
}
])
]
複製代碼
從新運行,你會發現默認樣式清除了!
使用教程 這裏已經很詳細了,本項目使用的是按需加載方式,能夠減少打包體積。
antd+react-router-dom
封裝導航組件咱們先看一下寫出來項目目錄
因爲代碼量愈來愈大,這裏再也不給出詳細代碼,若是須要請點擊 源碼 下載 release 1.0.0 版本
下面講一下這些目錄的用途
一、assets是資源目錄,放圖片,css,js,字體等等 二、blog是博客模塊的頁面 pages
目錄是blog
模塊下的頁面組件,在這裏新建了兩個頁面add.js
添加博客,list.js
博客列表 index.js
是管理bolg模塊的子路由的組件,代碼以下
import React from 'react'
import BlogListPage from "./pages/list"
import AddBlogPage from "./pages/add"
import { Route } from 'react-router-dom'
export default class BlogIndex extends React.Component {
render(){
return (
<div>
<p>BlogIndex</p>
<Route path="/blog/list" component={BlogListPage} />
<Route path="/blog/add" component={AddBlogPage} />
</div>
)
}
}
複製代碼
這裏使用<Route path="/blog/add" component={AddBlogPage} />
添加二級子路由,可是要注意,第一級路由是不要加exact
這個屬性,這個屬性表示精確匹配。若是父級路由加了這一屬性,子路由就會匹配不到。
舉個栗子: <Route exact={true} path="/blog" component={BlogIndex}>
若是這麼寫,當你輸入/blog/add
路徑,會匹配不到任何路由。只有當你輸入/blog
路徑時纔會匹配。能夠利用模糊匹配路徑方式實現多級路由的管理。
三、home目錄暫時沒用 四、layout整個項目的公用佈局組件 NavigationBar.js
是上邊的導航,SlideMenu.js
是側邊菜單 五、resume是當即模塊,沒有實現二級路由 六、user用戶管理模塊,和blog的目錄結構同樣,實現二級路由 七、app.less
是項目公用的樣式文件,這裏寫了導航和側邊欄的樣式 八、router.config.js
是項目的路由和左側菜單 九、router.js
是項目的路由和總體的佈局
實現的效果圖:
注意事項: 一、你會發現本項目html標籤使用class
屬性來代替className
屬性。react
自己的html
標籤是不支持class
屬性,只識別className
屬性編寫類名。這裏咱們須要安裝一個插件
npm install -D babel-plugin-react-html-attrs
複製代碼
而後再.babelrc
文件的pulgins
數組添加"react-html-attrs"
便可
二、咱們此處用的class
組件來編寫react
組件,若是有須要也可使用function
組件來編寫react
組件。當咱們使用class
的時候,再class
添加屬性時,也就是下邊的寫法,項目在編譯運行時報錯
export default class BlogIndex extends React.Component {
state = {
test:"name"
}
click = ()=>{
}
}
複製代碼
報錯以下:
解決方法是:
npm install -D @babel/plugin-proposal-class-properties
複製代碼
而後再.babelrc
文件的pulgins
數組添加"@babel/plugin-proposal-class-properties"
mobx
管理數據在react中使用mobx
,不只須要使用mobx
,還須要結合react的插件,那就是mobx-react
。 第一先安裝這兩個必須包
npm install -S mobx mobx-react
複製代碼
mobx
的基本用法請看這裏mobx mobx-react
是mobx
和react
的結合,提供Provider
組件統一管理mobx
數據;inject
爲react
組件注入某個mobx
實例;observer
實現mobx
實現react
組件和mobx
數據的雙向綁定(和react-redux
的connect
差很少)等等
mobx
實例並在react
入口文件引入咱們這裏在user目錄下先建store/UserList.js,建立管理用戶列表頁面的mobx實例
import { observable,action } from "mobx"
class UserListStore {
@observable name;
constructor(){
this.name = "my name is user list;";
}
}
export default new UserListStore();
複製代碼
下面咱們在src下新建store/index.js目錄,統一管理項目的mobx實例:
import UserListStore from "./../user/store/UserList"
const store = {
UserListStore
}
export default store;
複製代碼
在修改src/index.js,導入文件
import { Provider } from "mobx-react"
import store from "./store"
複製代碼
使用Provider
,store
<Provider {...store}>
<AppRouter />
</Provider>
複製代碼
從新運行項目,不出所料報錯。爲何呢?熟悉mobx
的同窗應該都知道,mobx
的特點是使用裝飾器來來修飾mobx實例中屬性和方法,以及react-mobx
也是經過裝飾器來使用。
裝飾器能夠經過@關鍵字加上相關的方法。來達到爲屬性,方法,class添加其它功能的做用。裝飾器做用的做用其實用很大,好比java
的spring
運用最普遍,想學習的同窗能夠去查相關資料。
咱們須要在項目配置對裝飾器的支持
安裝npm install -D @babel/plugin-proposal-decorators
,在.babelrc
文件的pulgins
數組添加
["@babel/plugin-proposal-decorators",{"legacy": true}], // 配置對裝飾器的支持
複製代碼
把"@babel/plugin-proposal-class-properties"
修改爲
["@babel/plugin-proposal-class-properties",{"loose":true}] // 支持類屬性的插件
複製代碼
注意這項配置必定要在@babel/plugin-proposal-decorators
以後,否則仍是同樣會報錯。
react
組件中使用mobx
經過inject
把須要的mobx
實例注入到react
組件
修改src/user/pages/list.js
import React from 'react'
import {withRouter} from 'react-router-dom'
import {Button} from "antd"
import { inject, observer } from "mobx-react"
@inject("UserListStore")
class UserListPage extends React.Component {
push = ()=>{
this.props.history.push("/user/add?name=231");
}
render(){
const {UserListStore} = this.props;
return (
<div>
<p>UserListPage</p>
<p>組件:{UserListStore.name}</p>
<Button onClick={this.push}>添加用戶</Button>
</div>
)
}
}
export default withRouter(UserListPage);
複製代碼
發現mobx
中的UserListStore
實例注入到this.props
中
使用observer
實現組件和數據的雙向綁定 在class組件使用@observer
修改組件,添加setName
方法
setName = ()=>{
const {UserListStore} = this.props;
UserListStore.setName("ha ha ha")
}
複製代碼
添加一個修更名稱的按鈕
<Button onClick={this.setName}>修更名字</Button>
複製代碼
點擊按鈕,你會發現{UserListStore.name}
變成了ha ha ha。這說明組件個數據雙向綁定已經成功
測試打包,一切正常!
引入mobx
代碼請下載 源碼 releases 1.0.1
mock
服務(node)爲了更好的模擬先後端分離場景,新搭建一個服務
項目根目錄建立mock
目錄,這裏使用koa
搭建一個node
服務。koa
搭建node
服務比較簡單,這裏就不說怎麼去搭建node
服務了。若是有須要能夠看我以前寫的react項目整合express+mock實現模擬接口數據,這裏只是express
框架換成了koa
框架。而後cd mock
,執行npm run dev
,服務正常啓動。端口好是8082。
重點說一下mock
,這裏咱們使用mockjs
模擬數據,須要在mock
目錄安裝mockjs
npm install -S mockjs
複製代碼
目錄結構:
咱們新建一個user模塊。user/data.js模擬數據庫的記錄。這裏模擬產生10條用戶記錄,只要生成了,就不會發生變化 user/data.js
const Mock = require("mockjs")
const data = Mock.mock({
'list|1-10': [{
'id|+1': 1,
'user_id|100-200': 1,
'status|1': true, // 狀態
'user_name': '@cname', // 名稱
'avatar': "@image('150x150', '#4A7BF7', 'img', 'png', 'Tiger')", // 頭像
'create_time': '@datetime("yyyy-MM-dd HH:mm:ss")', // 建立日期
}]
});
// 這裏模擬數據庫裏的用戶記錄
module.exports = data;
複製代碼
user/index.js內容以下
const Router = require("koa-router")
const router = new Router();
const Mock = require("mockjs")
const userlist = require("./data").list;
router.get("/api/user/list",async (ctx)=>{
ctx.body = {code:0,message:"success",userlist}
});
router.post("/api/user/add",async (ctx)=>{
let data = ctx.request.body;
data.id = userlist[userlist.length-1].id + 1;
const mock = Mock.mock({
'user_id|100-200': 1,
'status|1': false, // 狀態
'avatar': "@image('150x150', '#4A7BF7', 'img', 'png', 'Tiger')", // 頭像
'create_time': '@datetime("yyyy-MM-dd HH:mm:ss")', // 建立日期
})
data = Object.assign(data,mock);
userlist.push(data)
ctx.body = {code:0,message:"success"}
});
module.exports = router;
複製代碼
這裏模擬了請求用戶列表(沒有分頁),添加用戶接口。
postman請求接口數據,以下圖
react
項目請求mock
數據在前端項目安裝
npm install -S axios
複製代碼
由於涉及到跨域,咱們在開發環境須要在webpack.dev.config.js
的devServer屬性下添加代理
proxy: {
// 接口請求代理
"/api":{
secure: false,
target:"http://127.0.0.1:8082"
}
},
複製代碼
而後須要修改在src/user/store/UserList.js
,在這裏獲取請求用戶列表接口,並賦值給實例的userList屬性
import { observable,action } from "mobx"
import axios from "axios"
class UserListStore {
@observable userList;
constructor(){
this.userList = [];
}
@action
async getUserList(){
const config = {method:"get",url:"/api/user/list"};
const result = await axios(config);
if(result.data.code === 0){
const userList = result.data.data;
this.userList = userList;
}
}
}
export default new UserListStore();
複製代碼
在src/user/pages/list.js
頁面調用,和渲染用戶列表
componentDidMount(){
const {UserListStore} = this.props;
UserListStore.getUserList();
}
render(){
const {UserListStore} = this.props;
return (
<div>
{
UserListStore.userList.map((item,index)=><p key={index}>{item.user_name}</p>)
}
</div>
)
}
複製代碼
以下圖:
mock
+數據請求 源碼 releases 1.0.2
到這裏,react全家桶react+react-router+mobx+axios
的使用,mock
模擬後端數據已經完成。後邊的事情就是業務邏輯頁面的編輯(這裏省略),打包的優化(下一篇講述)。固然如今項目還有不少不完善,(模塊的組織,目錄結構的劃分,請求實例的封裝,試圖和業務邏輯的抽離,樣式的管理等等,這些和業務邏輯關聯性比較強,這裏不過多說明)
咱們執行一下npm run build
,打包成功。可是存在一個問題,打包出來的js高達1M多,太可怕了。如今這個項目還很簡單,隨着業務邏輯複雜和頁面的增多,打包的js會愈來愈大。下一篇文章咱們會一步步優化打包,從路由的懶加載,樣式的抽離,公用第三方包的抽離得等方面優化
下一篇:打包體積優化react+webpack4搭建前端項目(三)打包優化
react+webpack4+react-router5+react-loadable+mobx
系列文章請點擊
一、react+webpack4搭建前端項目(一)基礎項目搭建