導航:首頁 > 源碼編譯 > react按需編譯慢

react按需編譯慢

發布時間:2024-10-05 03:39:23

㈠ 從0搭建React+antd+TypeScript+Umi Hooks+Mobx前端框架

因為現在公司的主要技術棧是React,所以也想著能夠搭建一個好的React前端框架,方便在工作中使用;框架在打包過程也做了優化,多線程,拆包,緩存等等手段提升打包速度和質量。主要用到的庫包括:

創建帶TypeScript模板的react-app,推薦使用yarn,接下來我也主要以yarn做例子

然後在項目根目錄創建一個 craco.config.js 用於修改默認配置。antd按需載入以及自定義主題

重新打包就可以了, 所有的主題配置在這里噢

這里利用React-router做路由,同時也會根據用戶角色,做許可權處理;只有當角色和路由允許的角色一致時才可以訪問和展示。

新建router下新建indext.tsx 用於渲染頁面

引入Router/index.tsx

新建hasPermission.ts,如果頁面 roles 包括用戶的角色則返回true,在渲染menu和子頁面的時候就根據這個值渲染頁面。

比如Home頁面,渲染子頁面的邏輯:

在這里 SubPages1 下面的 page1 就無法展示出來和訪問,如果直接輸入路由也會訪問頁面不存在,因為page1允許的角色 user 而我們角色是 admin 所以無法展示。

useImmer 很好的解決了ReactHooks中的賦值的性能問題,可以單獨更新某個對象的某個屬性。

上面的賦值方法也可以寫到一起,效果是一樣的:

Umi Hooks 是一個 React Hooks 庫,致力提供常用且高質量的 Hooks。提供了非常多的Hooks組件,比如上面使用的 usePersistFn ,他的作用:在某些場景中,你可能會需要用 useCallback 記住一個回調,但由於內部函數必須經常重新創建,記憶效果不是很好,導致子組件重復 render。對於超級復雜的子組件,重新渲染會對性能造成影響。通過 usePersistFn ,可以保證函數地址永遠不會變化。Umi Hooks功能還是非常強大的,有很多功能很強大的API。大家可以去官方文檔看看 https://hooks.umijs.org/zh-CN/hooks/life-cycle/use-update-effect 。

自定義 hooks 其實在我們的開發工作中,還是很常遇到的。 hooks 的好處就是可以抽離公共方法,像組件一樣的隨意使用,對於快節奏的開發工作還是很舒服的,比如你覺得 react hooks 或者 umi hooks 的api,不能滿足自己的需求,也可以自己創新一些api。我這里舉個例子,大家寫 class 組件寫的很多的話,會經常用的 this.setState() ,大家都知道 this.setState() 是非同步執行,你無法直接拿到最新的 state 。 hooks 中的 useState 同樣也是非同步的,你無法直接獲取到最新的 state ,所以我自己寫了一個 useSetState 方法,用於在修改完狀態後能夠立即拿到最新的 state 。
我們在src/hooks文件夾下新建 useSetState.ts

使用的方式也很簡單,基本和useState一致,只是在setState的時候提供一個回調函數。

這就完成了帶回調的 useSetState hooks 的編寫,不過這種寫法不太推薦在 hooks 中使用,建議需要獲取最新的數值都在 useEffect 或者 useUpdateEffect(umi hooks) 中去。

狀態管理選擇的Mobx,Mobx和Rex我都用過,不過當我習慣用Mobx後,就感覺還是Mobx更方便一些,所以更喜歡在項目中用Mobx,現在Mobx已經更新到5.0版本了,不過5.0版本並不支持ie11,所以如果想要兼容性可以選擇4.0的版本,或者Rex。
這里推薦一個針對Mobx的庫, mobx-react-lite :它是基於 React 16.8 和 Hooks 的 MobX 的輕量級React綁定。

這個主要影響的是調用方法的形式,對於Mobx的書寫是一樣的,比如寫一個加減數值:

這里你的typeScirpt可能會編譯不了,會報錯:Experimental support for decorators is a feature that is subject to change in a future release. Set the 'experimentalDecorators' option in your 'tsconfig' or 'jsconfig' to remove this warning.
解決方法是在 tsconfig.json 加入配置:

完畢以後,一定要把 storeProvider 包裹所需要共享狀態的頁面,我這里直接放到app.tsx

剩下來就僅僅是調用的事情了:

此外axios的配置應該大家都知道,所以我這也不多說了,具體在我的源碼裡面也有,utils下的axios.ts

加入了打包分析 webpack-bundle-analyzer speed-measure-webpack-plugin
加入了打包進度條 webpackbar
加入了打包壓縮 compression-webpack-plugin terser-webpack-plugin
還對包進行拆包
開發環境的域名代理 devServer
加快打包速度,還可以考慮刪除antd-icons,單獨去iconfont網站下,按需引入。不然打包會費很多時間

引入dotenv-cli

新增開發環境配置文件 .env.development 和 .env.proction 兩個文件

然後修改package.json中的啟動腳本:

現在 yarn start 或者 yarn build 就會根據環境配置來處理。

還有一些細節的調整,會盡力將這個框架更加完善的。

github地址: https://github.com/Benzic/React-typescript-umihooks-mobx
歡迎star 和提意見

㈡ 【React入門實踐】結合Ant-Design 從0帶你手把手開發包含【列表】和【搜索欄】的簡單【用戶管理】頁面

寫在前面的話: 上節我們實現了簡單的是form表單,如下,今天我們來學習最常見的表單組件的使用。一步步向更復雜的頁面進發。

本次頁面核心知識點:(1)【search表單模塊】搜索search、重置功能reset、日期選擇器DatePicker、下拉框使用select;(2)【列表展示模塊】時間規范化moment、tag標簽的使用、省略款的Tooltip使用;

1. 看頁面需求

?分析:頁面分為兩個核心部分:【搜索欄】【列表】

2. 分析介面文檔

(1)留言列表介面-主要是在頁面初始化時調用。pageNum pageSize為請求參數,非必須。響應參數在list中。

?(2)搜索介面 - 但搜索介面一般可以直接使用列表介面即可

?

[]()?3. 參照UI編寫頁面代碼[]()(1) 列表部分

使用封裝的組件(代碼後附),data={listData}表示列表中綁定listData數據,注意dataIndex需要對照介面返回的參數編寫

dispatch,feedback: { listData, detailData },loading}: any) {const init = useCallback(() => {dispatch('feedback/init')}, [dispatch])useEffect(() => {init()}, [init])const columns = useMemo(() => [{title: '序號',dataIndex: '_id'},{title: '用戶名',dataIndex: 'username'},{title: '反饋標題',dataIndex: 'title'},{title: '反饋內容',dataIndex: 'content',},{title: '提交時間',dataIndex: 'createdTime',},{title: '狀態',dataIndex: 'status',},{title: '操作',render: (value: any) => (<>{value.status === 0 && (<a type="primary" onClick={() => toggleMessage(value.id)}>反饋留言</a>)}{value.status === 1 && (<a type="primary" onClick={() => toggleDetail(value.id)}>查看</a>)}</>)}],[toggleDetail, toggleMessage])return (<PageHeaderLayout className={'commonList'}><Search init={init} dispatch={dispatch} /><CardclassName={styles.table}style={{ marginTop: 1 }}bordered={false}bodyStyle={{ padding: Ǝpx 32px 32px 32px' }}><StandardTableloading={loading}data={listData}columns={columns}onChange={handleStandardTableChange}/></Card></PageHeaderLayout>)}(2)search查詢欄部分const { validateFields } = formconst simpleForm = useMemo(() => {const { getFieldDecorator, getFieldValue } = formconst { query } = getLocation()return (<Formlayout="inline"style={{ display: 'flex' }}className={styles.commonForm}><Form.Item label="">{getFieldDecorator('username', {initialValue: query.username})(<Input placeholder="用戶名" />)}</Form.Item><Form.Item label="">{getFieldDecorator('title', {initialValue: query.title})(<Input placeholder="標題" />)}</Form.Item><Form.Item label="">{getFieldDecorator('submitTimeBegin', {initialValue: query.startDate || ''})(<DatePickeronChange={change1}disabledDate={disabledDate1}placeholder="請選擇日期"/>)}</Form.Item><Form.Item label="">{getFieldDecorator('submitTimeEnd', {initialValue: query.startDate || ''})(<DatePickeronChange={change2}disabledDate={disabledDate2}placeholder="請選擇日期"/>)}</Form.Item><Form.Item>{getFieldDecorator('status', {initialValue: query.status || ''})(<Select><Option value={''}> 狀態 </Option>{feedbackStatus.map((v: any) => (<Option key={v.key} value={v.key}>{v.value}</Option>))}</Select>)}</Form.Item><Button className={styles.search} onClick={handleSearch} icon="search">查詢</Button><ButtonclassName={styles.reset}style={{ marginLeft: 10 }}onClick={handleFormReset}icon="undo">重置</Button></Form>)}, [form, handleFormReset, handleSearch, time1, time2])return (<Card bordered={false}><div className={'commonForm'}>{simpleForm}</div></Card>)})

可以看到,在頁面將search設置成組件,並在後面掉哦組件。至此已達到頁面效果,但是還沒有數據

4.初始化頁面 - 列表數據顯示

在page頁面的主函數中寫init函數

dispatch('feedback/init')}, [dispatch])useEffect(() => {init()}, [init])

在model頁面中寫詳細的介面調用信息

const { query } = getLocation()const data = await dispatch({type: 'feedback/post',params: ['manage/feedback/page', { ...query }]})dispatch({type: 'feedback/setStore',params: [{ listData: listMOM1(data) }]})},

其中我們使用到了ListMOM1組件來幫助頁面數據回顯,其主要功能是,添加頁面的數據編號和實現分頁功能,詳細的封裝代碼後附。 其中type: 'feedback/setStore',表示把數據存儲在緩存中,可以通過組件傳遞數據,因此在StandardTable中需要綁定data={listData},從而實現數據初始化顯示。

export const listMOM1 = (resData: any) => {const {content,// total,totalCount,currPage: currPage = 1,pageSize: pageSize = 40,data,list} = resDataconst list1 = content || data || list//添加序號if (list) {list.forEach((element: any, index: number) => {element._id = index + 1 + (currPage - 1) * pageSizeelement._symbol = element._id})}//分頁const pagination = {total: totalCount,pageSize: Number(pageSize) || 40,current: Number(currPage)}return {list,pagination: totalCount && { ...listData.pagination, ...pagination }}}5.列表數據按需渲染render

可以看到後台返回的數據如下,

但是,(1)【標題和內容】數據過長,我們需要將其展示前5個字元後省略號(比如這樣就。。。).(2)對於【日期】數據只需要顯示到具體某天,不需要時分秒,(3)對於【狀態】數據顯示為0,1但是前端也需要整理為『未回答』『已回答』

(1)數據截取縮略顯示,hover後顯示全部---使用Tooltip組件

title: '反饋內容',dataIndex: 'content',render: (text: any, record: any, index: any) => {if (record.content.length <= 5) {return record.content} else {return (<Tooltip title={record.content}>{record.content.substring(0, 5) + '...'}</Tooltip>)}}},

(2)日期截取同理

title: '提交時間',dataIndex: 'createdTime',render: (text: any, record: any, index: any) => {return record.createdTime.substring(0, 10)}},

(3)對於介面返回的0,1,2狀態數值數據需要分情況渲染

title: '狀態',dataIndex: 'status',render: (value: any) => (<>{value == 0 && <Tag color="red">未回答</Tag>}{value == 1 && <Tag color="green">已回答</Tag>}</>)},6. 查詢功能實現validateFields((err: any, data: any) => {// pushPath({// query: data// })// init()const res = { ...data }if (data.username !== undefined) {res.username = data.username.replace(/s*/g, '')}res.pageNum = 1dispatch({type: 'feedback/search',params: [res]})})}, [dispatch, validateFields])

對於按照日期的查詢需要做特殊處理。

(1)結束時間需要晚於開始時間

因此DataPicker組件中加入disableddata。

onChange={change1} disabledDate={disabledDate1} placeholder="請選擇日期"/>const { validateFields } = formconst simpleForm = useMemo(() => {const { getFieldDecorator, getFieldValue } = formconst { query } = getLocation()return (<Formlayout="inline"style={{ display: 'flex' }}className={styles.commonForm}><Form.Item label="">{getFieldDecorator('username', {initialValue: query.username})(<Input placeholder="用戶名" />)}</Form.Item><Form.Item label="">{getFieldDecorator('title', {initialValue: query.title})(<Input placeholder="標題" />)}</Form.Item><Form.Item label="">{getFieldDecorator('submitTimeBegin', {initialValue: query.startDate || ''})(<DatePickeronChange={change1}disabledDate={disabledDate1}placeholder="請選擇日期"/>)}</Form.Item><Form.Item label="">{getFieldDecorator('submitTimeEnd', {initialValue: query.startDate || ''})(<DatePickeronChange={change2}disabledDate={disabledDate2}placeholder="請選擇日期"/>)}</Form.Item><Form.Item>{getFieldDecorator('status', {initialValue: query.status || ''})(<Select><Option value={''}> 狀態 </Option>{feedbackStatus.map((v: any) => (<Option key={v.key} value={v.key}>{v.value}</Option>))}</Select>)}</Form.Item><Button className={styles.search} onClick={handleSearch} icon="search">查詢</Button><ButtonclassName={styles.reset}style={{ marginLeft: 10 }}onClick={handleFormReset}icon="undo">重置</Button></Form>)}, [form, handleFormReset, handleSearch, time1, time2])return (<Card bordered={false}><div className={'commonForm'}>{simpleForm}</div></Card>)})0

(2)提交時間格式處理

const { validateFields } = formconst simpleForm = useMemo(() => {const { getFieldDecorator, getFieldValue } = formconst { query } = getLocation()return (<Formlayout="inline"style={{ display: 'flex' }}className={styles.commonForm}><Form.Item label="">{getFieldDecorator('username', {initialValue: query.username})(<Input placeholder="用戶名" />)}</Form.Item><Form.Item label="">{getFieldDecorator('title', {initialValue: query.title})(<Input placeholder="標題" />)}</Form.Item><Form.Item label="">{getFieldDecorator('submitTimeBegin', {initialValue: query.startDate || ''})(<DatePickeronChange={change1}disabledDate={disabledDate1}placeholder="請選擇日期"/>)}</Form.Item><Form.Item label="">{getFieldDecorator('submitTimeEnd', {initialValue: query.startDate || ''})(<DatePickeronChange={change2}disabledDate={disabledDate2}placeholder="請選擇日期"/>)}</Form.Item><Form.Item>{getFieldDecorator('status', {initialValue: query.status || ''})(<Select><Option value={''}> 狀態 </Option>{feedbackStatus.map((v: any) => (<Option key={v.key} value={v.key}>{v.value}</Option>))}</Select>)}</Form.Item><Button className={styles.search} onClick={handleSearch} icon="search">查詢</Button><ButtonclassName={styles.reset}style={{ marginLeft: 10 }}onClick={handleFormReset}icon="undo">重置</Button></Form>)}, [form, handleFormReset, handleSearch, time1, time2])return (<Card bordered={false}><div className={'commonForm'}>{simpleForm}</div></Card>)})1

並在查詢函數中添加time時間格式處理

const { validateFields } = formconst simpleForm = useMemo(() => {const { getFieldDecorator, getFieldValue } = formconst { query } = getLocation()return (<Formlayout="inline"style={{ display: 'flex' }}className={styles.commonForm}><Form.Item label="">{getFieldDecorator('username', {initialValue: query.username})(<Input placeholder="用戶名" />)}</Form.Item><Form.Item label="">{getFieldDecorator('title', {initialValue: query.title})(<Input placeholder="標題" />)}</Form.Item><Form.Item label="">{getFieldDecorator('submitTimeBegin', {initialValue: query.startDate || ''})(<DatePickeronChange={change1}disabledDate={disabledDate1}placeholder="請選擇日期"/>)}</Form.Item><Form.Item label="">{getFieldDecorator('submitTimeEnd', {initialValue: query.startDate || ''})(<DatePickeronChange={change2}disabledDate={disabledDate2}placeholder="請選擇日期"/>)}</Form.Item><Form.Item>{getFieldDecorator('status', {initialValue: query.status || ''})(<Select><Option value={''}
閱讀全文

與react按需編譯慢相關的資料

熱點內容
破解的系統怎麼用銀行app 瀏覽:263
java三層架構mvc 瀏覽:880
徐州編程教育加盟 瀏覽:899
蘋果手機臉書app如何設置中文 瀏覽:538
pdf文件在線修改 瀏覽:399
伺服器上如何搭建自己的網站 瀏覽:467
雲南省青少年學習編程 瀏覽:480
c工程的編譯時間 瀏覽:587
java判斷字元串包含某個字元串中 瀏覽:977
3匹單相谷輪壓縮機用多大的電容 瀏覽:784
比心app怎麼樣用 瀏覽:741
和平精英怎麼改國際服的伺服器 瀏覽:946
手機存儲卡128是哪個文件夾 瀏覽:180
安北解壓包密碼 瀏覽:651
阿里巴巴app靜態編譯 瀏覽:725
命令世界怎麼獲得迷你幣 瀏覽:651
應用加密重新安裝 瀏覽:83
抖音抖幣充值源碼 瀏覽:736
我的世界如何去更新伺服器 瀏覽:76
單片機視頻模塊 瀏覽:996