前言
react+webpack4搭建前端項目分為三個章節(jié)贺奠。鏈接如下。目的是實現(xiàn)從零搭建一個react后臺管理系統(tǒng)
1粘咖、react+webpack4搭建前端項目(一)基礎項目搭建
2、react+webpack4搭建前端項目(二)react全家桶的使用
3、react+webpack4搭建前端項目(三)打包優(yōu)化
webpack配置的講解
4吩谦、react+webpack4.x搭建前端項目(四)配置抽取和區(qū)分環(huán)境
5、react+webpack4.x搭建前端項目(五)多頁面配置
6膝藕、react+webpack4.x多模塊打包配置
這是第二章式廷,react全家桶的使用
這里小編推薦一個福利,更多精彩內容請點擊鏈接芭挽,點擊這里
廢話不多說啦滑废。接著上一篇react+webpack4搭建前端項目(一)我們正式進入react
全家桶技術篇章,如果對于項目不清楚或者在下面有什么疑惑袜爪,建議先看一下上一篇文章熟悉一下項目由來
使用react-router-dom
管理路由蠕趁,這里使用react-router4.x以后的版本,請注意辛馆,和3.x的使用還是有很大的區(qū)別
npm install -S react-router-dom
我們?yōu)槭裁词褂?code>react-router-dom呢俺陋?
先簡單說下各自的功能:
react-router
: 實現(xiàn)了路由的核心功能
react-router-dom
: 基于react-router
,加入了在瀏覽器運行環(huán)境下的一些功能怀各,例如:Link
組件倔韭,會渲染一個a
標簽,BrowserRouter
和HashRouter
組件瓢对。顯而易見react-router-dom
功能更豐富寿酌,所以選擇react-router-dom
代替react-router
下面接著上一篇文章的項目,我們對項目進行改造:
新建blog硕蛹,resume醇疼,user頁面,如下
分別編寫
blog法焰,resume秧荆,user,home
(上篇文章已完成)組件
此處刪除home/index.less
埃仪,修改home/index.js
內容:
import React from 'react'
export default class HomeIndex extends React.Component {
render(){
return (
<div>
<p>HomeIndex</p>
</div>
)
}
}
blog/index.js
import React from 'react'
export default class BlogIndex extends React.Component {
render(){
return (
<div>
<p>BlogIndex</p>
</div>
)
}
}
resume/index.js
import React from 'react'
export default class ResumeIndex extends React.Component {
render(){
return (
<div>
<p>ResumeIndex</p>
</div>
)
}
}
user/index.js
import React from 'react'
export default class UserIndex extends React.Component {
render(){
return (
<div>
<p>UserIndex</p>
</div>
)
}
}
以上這些組件是最簡單的組件
新建src/router.js
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
基本使用已經(jīng)完成忱反。
因為我們這里是配合項目使用,詳細的react-router-dom
不過多講解滤愕,如果想學習更多基本用法温算,請查看官方文檔。在后邊隨著項目的復雜该互,后邊我們還會說一下嵌套路由米者,頁面之間的跳轉等等使用方法。
最后我們需要清除頁面宇智,標簽的默認樣式蔓搞。代碼可以去網(wǎng)上找一份,網(wǎng)上隨處可見随橘。
然后在項目根目錄新建static/css/reset.min.css喂分,在index.html模板引入
<link rel="stylesheet" href="/static/css/reset.min.css">
重新運行,你會發(fā)現(xiàn)找不到/static/css/reset.min.css
机蔗。因為這里只是在index.html
中引入了文件蒲祈,但是并沒有在webpack
中處理靜態(tài)文件,我們需要把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: ['.*']
}
])
]
重新運行,你會發(fā)現(xiàn)默認樣式清除了牙言!
引入antd
使用教程
這里已經(jīng)很詳細了酸钦,本項目使用的是按需加載方式,可以減小打包體積咱枉。
使用antd+react-router-dom
封裝導航組件
我們先看一下寫出來項目目錄
由于代碼量越來越大卑硫,這里不再給出詳細代碼,如果需要請點擊 源碼 下載 release 1.0.0 版本
下面講一下這些目錄的用途
1蚕断、assets是資源目錄欢伏,放圖片,css亿乳,js硝拧,字體等等
2、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
路徑時才會匹配朋凉。可以利用模糊匹配路徑方式實現(xiàn)多級路由的管理州丹。
3、home目錄暫時沒用
4杂彭、layout整個項目的公用布局組件 NavigationBar.js
是上邊的導航墓毒,SlideMenu.js
是側邊菜單
5、resume是立即模塊亲怠,沒有實現(xiàn)二級路由
6所计、user用戶管理模塊,和blog的目錄結構一樣团秽,實現(xiàn)二級路由
7主胧、app.less
是項目公用的樣式文件,這里寫了導航和側邊欄的樣式
8习勤、router.config.js
是項目的路由和左側菜單
9踪栋、router.js
是項目的路由和整體的布局
實現(xiàn)的效果圖:
注意事項:
1、你會發(fā)現(xiàn)本項目html標簽使用class
屬性來代替className
屬性图毕。react
本身的html
標簽是不支持class
屬性夷都,只識別className
屬性編寫類名。這里我們需要安裝一個插件
npm install -D babel-plugin-react-html-attrs
然后再.babelrc
文件的pulgins
數(shù)組添加"react-html-attrs"
即可
2吴旋、我們此處用的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
數(shù)組添加"@babel/plugin-proposal-class-properties"
使用mobx
管理數(shù)據(jù)
在react中使用mobx
笆焰,不僅需要使用mobx
劫谅,還需要結合react的插件,那就是mobx-react
嚷掠。
第一先安裝這兩個必須包
npm install -S mobx mobx-react
mobx
的基本用法請看這里mobx
mobx-react
是mobx
和react
的結合捏检,提供Provider
組件統(tǒng)一管理mobx
數(shù)據(jù);inject
為react
組件注入某個mobx
實例不皆;observer
實現(xiàn)mobx
實現(xiàn)react
組件和mobx
數(shù)據(jù)的雙向綁定(和react-redux
的connect
差不多)等等
創(chuàng)建mobx
實例并在react
入口文件引入
我們這里在user目錄下先建store/UserList.js贯城,創(chuàng)建管理用戶列表頁面的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目錄,統(tǒng)一管理項目的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
數(shù)組添加
["@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);
發(fā)現(xiàn)mobx
中的UserListStore
實例注入到this.props
中
使用observer
實現(xiàn)組件和數(shù)據(jù)的雙向綁定
在class組件使用@observer
修改組件,添加setName
方法
setName = ()=>{
const {UserListStore} = this.props;
UserListStore.setName("ha ha ha")
}
添加一個修改名稱的按鈕
<Button onClick={this.setName}>修改名字</Button>
點擊按鈕西壮,你會發(fā)現(xiàn){UserListStore.name}
變成了ha ha ha遗增。這說明組件個數(shù)據(jù)雙向綁定已經(jīng)成功
測試打包,一切正常款青!
引入mobx
代碼請下載 源碼 releases 1.0.1
搭建mock
服務(node)
為了更好的模擬前后端分離場景做修,新搭建一個服務
項目根目錄創(chuàng)建mock
目錄,這里使用koa
搭建一個node
服務抡草。koa
搭建node
服務比較簡單饰及,這里就不說怎么去搭建node
服務了。如果有需要可以看我之前寫的react項目整合express+mock實現(xiàn)模擬接口數(shù)據(jù)康震,這里只是express
框架換成了koa
框架燎含。然后cd mock
沐扳,執(zhí)行npm run dev
每辟,服務正常啟動废境。端口好是8082赐稽。
重點說一下mock
,這里我們使用mockjs
模擬數(shù)據(jù)顷扩,需要在mock
目錄安裝mockjs
npm install -S mockjs
目錄結構:
我們新建一個user模塊规惰。user/data.js模擬數(shù)據(jù)庫的記錄空厌。這里模擬產(chǎn)生10條用戶記錄钝诚,只要生成了颖御,就不會發(fā)生變化
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, // 狀態(tài)
'user_name': '@cname', // 名稱
'avatar': "@image('150x150', '#4A7BF7', 'img', 'png', 'Tiger')", // 頭像
'create_time': '@datetime("yyyy-MM-dd HH:mm:ss")', // 創(chuàng)建日期
}]
});
// 這里模擬數(shù)據(jù)庫里的用戶記錄
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, // 狀態(tài)
'avatar': "@image('150x150', '#4A7BF7', 'img', 'png', 'Tiger')", // 頭像
'create_time': '@datetime("yyyy-MM-dd HH:mm:ss")', // 創(chuàng)建日期
})
data = Object.assign(data,mock);
userlist.push(data)
ctx.body = {code:0,message:"success"}
});
module.exports = router;
這里模擬了請求用戶列表(沒有分頁),添加用戶接口凝颇。
postman請求接口數(shù)據(jù)潘拱,如下圖
react
項目請求mock
數(shù)據(jù)
在前端項目安裝
npm install -S axios
因為涉及到跨域秉继,我們在開發(fā)環(huán)境需要在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
+數(shù)據(jù)請求 源碼 releases 1.0.2
到這里辑鲤,react全家桶react+react-router+mobx+axios
的使用盔腔,mock
模擬后端數(shù)據(jù)已經(jīng)完成。后邊的事情就是業(yè)務邏輯頁面的編輯(這里省略)月褥,打包的優(yōu)化(下一篇講述)弛随。當然現(xiàn)在項目還有很多不完善,(模塊的組織宁赤,目錄結構的劃分舀透,請求實例的封裝,試圖和業(yè)務邏輯的抽離决左,樣式的管理等等愕够,這些和業(yè)務邏輯關聯(lián)性比較強,這里不過多說明)
我們執(zhí)行一下npm run build
佛猛,打包成功惑芭。但是存在一個問題,打包出來的js高達1M多继找,太可怕了∷旄現(xiàn)在這個項目還很簡單,隨著業(yè)務邏輯復雜和頁面的增多婴渡,打包的js會越來越大幻锁。下一篇文章我們會一步步優(yōu)化打包,從路由的懶加載边臼,樣式的抽離哄尔,公用第三方包的抽離得等方面優(yōu)化
下一篇: react+webpack打包優(yōu)化react+webpack4搭建前端項目(三)打包優(yōu)化