react+webpack4搭建前端項目(二)react全家桶的使用

前言

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標簽,BrowserRouterHashRouter組件瓢对。顯而易見react-router-dom功能更豐富寿酌,所以選擇react-router-dom代替react-router

下面接著上一篇文章的項目,我們對項目進行改造:
新建blog硕蛹,resume醇疼,user頁面,如下

QQ截圖20190813113835.png

分別編寫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亏掀,效果如圖

1565673235831.gif

到此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封裝導航組件

我們先看一下寫出來項目目錄

QQ截圖20190815182309.png

由于代碼量越來越大卑硫,這里不再給出詳細代碼,如果需要請點擊 源碼 下載 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)的效果圖:

QQ截圖20190816085339.png

注意事項:
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 = ()=>{   
    }
}

報錯如下:

QQ截圖20190813152902.png

解決方法是:

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-reactmobxreact的結合捏检,提供Provider組件統(tǒng)一管理mobx數(shù)據(jù);injectreact組件注入某個mobx實例不皆;observer實現(xiàn)mobx實現(xiàn)react組件和mobx數(shù)據(jù)的雙向綁定(和react-reduxconnect差不多)等等

創(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添加其它功能的作用排苍。裝飾器作用的作用其實用很大,比如javaspring運用最廣泛税弃,想學習的同學可以去查相關資料纪岁。

我們需要在項目配置對裝飾器的支持

安裝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

QQ截圖20190816104214.png

使用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

目錄結構:


QQ截圖20190816144713.png

我們新建一個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ù)潘拱,如下圖

QQ截圖20190816143728.png
QQ截圖20190816150900.png

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>
    )
}

如下圖:


QQ截圖20190816153402.png

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)化

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市硼瓣,隨后出現(xiàn)的幾起案子究飞,更是在濱河造成了極大的恐慌,老刑警劉巖堂鲤,帶你破解...
    沈念sama閱讀 206,311評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件亿傅,死亡現(xiàn)場離奇詭異,居然都是意外死亡瘟栖,警方通過查閱死者的電腦和手機葵擎,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,339評論 2 382
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來半哟,“玉大人酬滤,你說我怎么就攤上這事签餐。” “怎么了盯串?”我有些...
    開封第一講書人閱讀 152,671評論 0 342
  • 文/不壞的土叔 我叫張陵氯檐,是天一觀的道長。 經(jīng)常有香客問我体捏,道長冠摄,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,252評論 1 279
  • 正文 為了忘掉前任几缭,我火速辦了婚禮河泳,結果婚禮上,老公的妹妹穿的比我還像新娘年栓。我一直安慰自己拆挥,他們只是感情好,可當我...
    茶點故事閱讀 64,253評論 5 371
  • 文/花漫 我一把揭開白布某抓。 她就那樣靜靜地躺著纸兔,像睡著了一般。 火紅的嫁衣襯著肌膚如雪否副。 梳的紋絲不亂的頭發(fā)上食拜,一...
    開封第一講書人閱讀 49,031評論 1 285
  • 那天,我揣著相機與錄音副编,去河邊找鬼负甸。 笑死,一個胖子當著我的面吹牛痹届,可吹牛的內容都是我干的呻待。 我是一名探鬼主播,決...
    沈念sama閱讀 38,340評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼队腐,長吁一口氣:“原來是場噩夢啊……” “哼蚕捉!你這毒婦竟也來了?” 一聲冷哼從身側響起柴淘,我...
    開封第一講書人閱讀 36,973評論 0 259
  • 序言:老撾萬榮一對情侶失蹤迫淹,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后为严,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體敛熬,經(jīng)...
    沈念sama閱讀 43,466評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 35,937評論 2 323
  • 正文 我和宋清朗相戀三年第股,在試婚紗的時候發(fā)現(xiàn)自己被綠了应民。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,039評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖诲锹,靈堂內的尸體忽然破棺而出繁仁,到底是詐尸還是另有隱情,我是刑警寧澤归园,帶...
    沈念sama閱讀 33,701評論 4 323
  • 正文 年R本政府宣布黄虱,位于F島的核電站,受9級特大地震影響庸诱,放射性物質發(fā)生泄漏悬钳。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,254評論 3 307
  • 文/蒙蒙 一偶翅、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧碉渡,春花似錦聚谁、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,259評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至习霹,卻和暖如春朵耕,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背淋叶。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評論 1 262
  • 我被黑心中介騙來泰國打工阎曹, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人煞檩。 一個月前我還...
    沈念sama閱讀 45,497評論 2 354
  • 正文 我出身青樓处嫌,卻偏偏與公主長得像,于是被迫代替她去往敵國和親斟湃。 傳聞我的和親對象是個殘疾皇子熏迹,可洞房花燭夜當晚...
    茶點故事閱讀 42,786評論 2 345