知識(shí)
不管是網(wǎng)站,軟件還是小程序,都要直接或間接能為您產(chǎn)生價(jià)值,我們?cè)谧非笃湟曈X(jué)表現(xiàn)的同時(shí),更側(cè)重于功能的便捷,營(yíng)銷(xiāo)的便利,運(yùn)營(yíng)的高效,讓網(wǎng)站成為營(yíng)銷(xiāo)工具,讓軟件能切實(shí)提升企業(yè)內(nèi)部管理水平和效率。優(yōu)秀的程序?yàn)楹笃谏?jí)提供便捷的支持!
您當(dāng)前位置>首頁(yè) » 新聞資訊 » 小程序相關(guān) >
微信H5 React + Umi 開(kāi)發(fā)實(shí)踐總結(jié)
發(fā)表時(shí)間:2021-1-5
發(fā)布人:葵宇科技
瀏覽次數(shù):219
最近一直在做H5公眾號(hào)的需求,使用的技術(shù)棧如標(biāo)題,從立項(xiàng)目到穩(wěn)定增長(zhǎng)階段,前端使用React隨著業(yè)務(wù)需求從0到1把項(xiàng)目搭建起來(lái),get了很多React+H5+微信場(chǎng)景下的知識(shí)點(diǎn),把最近的實(shí)踐總結(jié)下,有需要使用React上手微信H5的可以參考,大家一起交流哈。
本文特點(diǎn):
- React+H5+微信場(chǎng)景全流程。
- Vue轉(zhuǎn)React入門(mén)參考。
項(xiàng)目簡(jiǎn)介:
轎車(chē)物流平臺(tái),可以通過(guò)公眾號(hào)在線(xiàn)完成轎車(chē)運(yùn)輸下單業(yè)務(wù)。
- 線(xiàn)路價(jià)格查詢(xún)
- 下單信息填寫(xiě)
- 地址簿管理
- 實(shí)名認(rèn)證
- 銀行卡綁定
- 優(yōu)惠券
- 微信支付
- 活動(dòng)海報(bào)
正文
-
區(qū)分Umi與Dva
-
Umi配置
-
React常用寫(xiě)法
-
Dva使用入門(mén)
-
微信配置
-
TypeScript組件
-
H5小技巧
-
日志記錄
-
其他
1. 區(qū)分Umi與Dva
剛從Vue轉(zhuǎn)React時(shí),很容易分不清楚Umi和Dva,從官網(wǎng)文檔看都自稱(chēng)為應(yīng)用框架,(大佬跳過(guò))。
Umi
不嚴(yán)謹(jǐn)?shù)恼f(shuō):可以理解為類(lèi)Vue-cli腳手架,幫你生成了帶router的項(xiàng)目模板,開(kāi)箱即用。整合了router + antd,還有一些國(guó)際化、配置式路由等功能深度整合的。
Dva
不嚴(yán)謹(jǐn)?shù)恼f(shuō):可以理解為類(lèi)Vuex的狀態(tài)管理庫(kù)。整合了 redux + reduxsaga。
為什么是Umi + Dva
在用Vue開(kāi)發(fā)時(shí),我們更傾向于vue-cli創(chuàng)建模板、Vuex狀態(tài)管理。
而且Umi
比React官方腳手架create-react-app
更強(qiáng)大、更貼近業(yè)務(wù)場(chǎng)景,開(kāi)箱即用。
React在狀態(tài)管理上有redux
,不夠好用又出現(xiàn)redux-saga
,最后被Dva
打包成更好用的數(shù)據(jù)流方案。
2. Umi配置
Umi配置很強(qiáng)大,列一下用到的幾個(gè)重要配置,詳細(xì)配置可參見(jiàn)官網(wǎng)配置。
環(huán)境變量
前端根據(jù)環(huán)境變量打包不同環(huán)境代碼,如Api地址、靜態(tài)資源地址等。
分支 | 打包腳本 | 環(huán)境 | Api地址 | 靜態(tài)資源地址 |
---|---|---|---|---|
Maser | build:test | 測(cè)試 | fat.*.com | cdn.fat.*.com |
Develop | build:prod | 正式 | *.com | cdn.*.com |
// package.json
{
"scripts": {
"start": "cross-env APP_TYPE=site BUILD_ENV=dev PORT=80 umi dev",
"build": "umi build",
"build:test": "BUILD_ENV=test umi build",
"build:prod": "BUILD_ENV=prod umi build",
},
}
復(fù)制代碼
umi-plugin-react配置
是官方的一個(gè)針對(duì)react的插件,頁(yè)面按需加載、rem適配在這里配置。
dynamicImport
指定進(jìn)入頁(yè)面時(shí)的loading組件。hd
開(kāi)啟rem方案
微信開(kāi)發(fā)務(wù)必關(guān)掉
pwa
選項(xiàng),否則導(dǎo)致上線(xiàn)后緩存嚴(yán)重。
其他配置
PostCSS/按需加載/主題/proxy代理等。
代碼
import pageRoutes from './router.config';
import theme from '../src/theme';
import webpackPlugin from './plugin.config';
const plugins = [
[
'umi-plugin-react',
{
antd: true,
dva: {
hmr: true,
},
dynamicImport: { //
loadingComponent: './components/PageLoading/index',
webpackChunkName: true,
},
pwa: false,
title: {
defaultTitle: '默認(rèn)標(biāo)題',
},
dll: false,
hd: true,
fastClick: false,
routes: {
exclude: [],
},
hardSource: false,
},
],
];
const env = process.env.BUILD_ENV,
publicPath = {
"dev": "",
"test": "http://*.fat.*.com/",
"prod": "http://*.*.com/"
}[env];
const apiPath = {
"dev": 'http://*.feature.*.com/api',
"test": 'http://*.fat.*.com/api',
"prod": 'https://*.*.com/api'
}[env];
export default {
base: '/',
publicPath: publicPath,
define: {
APP_TYPE: process.env.APP_TYPE || '',
apiPath: apiPath || '',
},
// history: 'hash', // 默認(rèn)是 browser
plugins,
routes: pageRoutes,
theme: { // 主題
'brand-primary': theme.primaryColor,
'brand-primary-tap': theme.brandPrimaryTap,
},
externals: {},
lessLoaderOptions: {
javascriptEnabled: true,
},
targets: {
android: 5,
chrome: 58,
edge: 13,
firefox: 45,
ie: 9,
ios: 7,
safari: 10,
},
outputPath: './dist',
hash: true,
alias: {},
proxy: { // 代理
'/api/': {
changeOrigin: true,
target: 'http://doclever.xin.com/mock/5d0b67ac3eb3ea0008d58a31',
},
},
ignoreMomentLocale: true,
manifest: {
basePath: '/',
},
chainWebpack: webpackPlugin,
extraPostCSSPlugins: [ // postcss插件
require('postcss-flexbugs-fixes'),
],
es5ImcompatibleVersions: true,
extraBabelPlugins: [
['import', { libraryName: 'antd-mobile', style: true }] //按需加載antd-mobile樣式文件
],
};
復(fù)制代碼
3. React常用寫(xiě)法
Vue轉(zhuǎn)React后,沒(méi)有v-for/v-if
等指令,還是稍微轉(zhuǎn)化下寫(xiě)法。
map代替v-for指令
const arr = ['aaa','bbb','ccc'];
arr.map(str => <div>{str}div>);
復(fù)制代碼
邏輯運(yùn)算符號(hào)代替與v-if/v-else
const show = false;
render (){
return <>
{show && <div>我展示了div>}
{show ? <div>為true展示div> : <div>為false展示div>}
};
復(fù)制代碼
路由跨頁(yè)面?zhèn)鲄?/h4>
Vue中使用this.$route.params
可以直接獲取參數(shù),在React中只有通過(guò)withRouter
包裹的組件才能獲得路由參數(shù),BasicLayout
中統(tǒng)一包裹頁(yè)面級(jí)組件,但內(nèi)面內(nèi)嵌套的組件如需獲取路由參數(shù)則要自己手動(dòng)包裹。
import { withRouter } from 'react-router-dom'
class FixBar extends React.Component{
public render() {
const { location: { query = {} }, } = this.props;
return (<div>{query.id || '默認(rèn)文字'}div>);
}
}
export default withRouter(FixBarCom);
復(fù)制代碼
監(jiān)聽(tīng)props/state變化
在Vue中可以使用watch
api方便的監(jiān)聽(tīng)參數(shù)變化,因?yàn)閷?shí)現(xiàn)原理不同,React需要借助其他Api實(shí)現(xiàn)類(lèi)似功能。
getDerivedStateFromProps
不常用,即state
的值在任何時(shí)候都取決于props
的情況下使用。
componentDidUpdate(prevProps, prevState) {
// 監(jiān)聽(tīng)props
if (this.props.userID !== prevProps.userID) {
// doSomething
}
// 監(jiān)聽(tīng)state
if (this.state.name !== prevState.name) {
// doSomething
}
}
復(fù)制代碼
setState與fiber
為了更好的性能,react采用了fiber架構(gòu),意味著setState操作可能是異步的。
// 不推薦
this.setState({ a:1})
this.setState({ a:this.state.a + 1})
// 推薦
this.setState({a:1},() => {
this.setState({ a:this.state.a + 1})
})
// 不推薦
this.setState({
counter: this.state.counter + this.props.increment,
});
// 推薦
this.setState((state, props) => ({
counter: state.counter + props.increment
}));
復(fù)制代碼
ES6結(jié)合setState的一些寫(xiě)法:
const data = http://www.wxapp-union.com/{ a: '11' }
this.setState({ ...data })
this.setState({ a:'222'})
this.setState({ ['a']: '333' })
this.setState((prevState, props) => ({a: '444' }));
復(fù)制代碼
React debounce 防抖
很多場(chǎng)景下需要對(duì)Input
的onChage
事件增加防抖,借助lodash.debounce
方法。
import _ from 'lodash';
class DebounceExample extends React.Component {
constructor(props) {
this.handleInputThrottled = _.debounce(this.getSomeFn, 100)
}
getSomeFn(res){
// doSomeThing
}
render() {
return <input onChange={this.handleInputThrottled}/>
}
}
export defaultDebounceExample;
復(fù)制代碼
React createPortal
部分場(chǎng)景需要把子元素的內(nèi)容節(jié)點(diǎn)放在其他組件里,比如彈框組件,每次彈框都希望在body
元素的根節(jié)點(diǎn)下,就可以使用createPortal
。
官方解釋?zhuān)?/p>
Portal 提供了一種將子節(jié)點(diǎn)渲染到存在于父組件以外的 DOM 節(jié)點(diǎn)的優(yōu)秀的方案。
舉個(gè)例子說(shuō)明,我們的需求是A/B2個(gè)輸入框組件,他們的下拉結(jié)果要通知展示在父組件下。
如圖:
// 父組件
<inputCom />
<div id="listBox">div>
// inputCom
class InputCom extends React.Component{
ExternalCityComp(){
return return ReactDOM.createPortal(<div>結(jié)果div>,document.querySelector('#listBox'))
}
public render() {
return (<div><input onChage={}/>{this.ExternalCityComp()}div>);
}
}
復(fù)制代碼
static靜態(tài)方法
React組件可以設(shè)置靜態(tài)方法,比如實(shí)現(xiàn)類(lèi)似Toast組件的方法。
class Toast extends React.Component {
...
static success(Param) { // do something }
static fail(Param) { // do something }
...
}
Toast.success()
Toast.fail()
復(fù)制代碼
className 樣式
const s = require('./index.less');
render (){
const active = true
return <>
<li className={`${s.inputItem} ${s.borderBottom}`}>li>
<li className={`${active ? s.inputItem : s.other } ${s.borderBottom}`}>li>
}
復(fù)制代碼
圖片引用
import btnImg from './images/floatBtn.png';
render (){
return <img src={btnImg} />
}
復(fù)制代碼
4. Dva使用入門(mén)
在用Dva
之前,總就覺(jué)得和Vuex
的用法差不了多少,但是初次使用時(shí),啃了半天Dva
的文檔,還是被繞的暈暈的;
其實(shí)并不復(fù)雜,今天就寫(xiě)下如何在不懂redux
、redux-saga
的情況下,愉快的使用Dva
,大神自行跳過(guò)。
文件目錄
我們只需要關(guān)注三個(gè)目錄下的文件就可以了。
- 頁(yè)面:
src/pages
- 模型:
src/models
- 服務(wù):
src/services
頁(yè)面即我們?cè)诼酚芍性黾拥捻?yè)面組件,模型是重點(diǎn),服務(wù)說(shuō)白了就是封裝的request
請(qǐng)求。
異步請(qǐng)求、同步請(qǐng)求
- 我們把models當(dāng)做一個(gè)全局變量,可以存放數(shù)據(jù),可以被任何頁(yè)面獲取,存和取都有對(duì)應(yīng)的Api。
- 存數(shù)據(jù)有2中方式,一種是直接把數(shù)據(jù)存到
models
里(同步請(qǐng)求),另一種是發(fā)一個(gè)請(qǐng)求然后把數(shù)據(jù)存到models
里(異步請(qǐng)求)。 - 同步請(qǐng)求即
reducers
里的方法,會(huì)修改models.state
里的數(shù)據(jù)。 - 異步請(qǐng)求即調(diào)用
models
的effects
方法,該方法會(huì)調(diào)用services
方法獲取請(qǐng)求數(shù)據(jù)。 - 異步請(qǐng)求在拿到
services
返回的數(shù)據(jù)后,如果要保存到models.state
里,則再調(diào)用同步方法reducers
即可。
再加深下印象:同步即直接保存、異步即發(fā)請(qǐng)求然后保存。
頁(yè)面獲取models
數(shù)據(jù)
頁(yè)面通過(guò)dva.connect
方法 + models.namespace
(每個(gè)models有自己的命名空間)獲取數(shù)據(jù)。
connect
方法的主要作用是把models
里的數(shù)據(jù)合并到頁(yè)面組件的props
里。
代碼中列舉了三種不同的調(diào)用語(yǔ)法,如果覺(jué)的看ES6
的裝飾器+解構(gòu)+箭頭函數(shù)不直觀(guān),可以看代碼中的ES5
版本。
代碼:
import React from 'react';
import { connect } from 'dva';
// 版本1 裝飾器語(yǔ)法
@connect(({ list:{ payInfo, detail } }) => ({ payInfo, detail }))
class PayInfo extends React.Component<ITextPaperProps, IEntranceState, any> {
public render() {
// 從props中獲取
const { payInfo, detail } = this.props;
return (
<div >
{payInfo}
div>
);
}
}
export default PayInfo;
// 版本2 函數(shù)
export default connect(
({ list:{ payInfo, detail } }) => ({ payInfo, detail }))(PayInfo);
// 版本3 ES5函數(shù)
export default connect(function(modules){
return {
payInfo: modules.list.payInfo,
detail: modules.list.detail
}
})(PayInfo);
復(fù)制代碼
頁(yè)面調(diào)用models
請(qǐng)求
頁(yè)面中通過(guò)dispatch
方法調(diào)用請(qǐng),同步和異步的調(diào)用形式一樣,只是在module
中的處理不一樣,下邊展示完整的代碼。
page
代碼:
import React from 'react';
import { connect } from 'dva';
// 版本1 裝飾器語(yǔ)法
@connect(({ list:{ payInfo, detail } }) => ({ payInfo, detail }))
class PayInfo extends React.Component<ITextPaperProps, IEntranceState, any> {
// 異步調(diào)用
setPayInfo(){
const { dispatch } = props;
dispatch({
type: 'list/setPayInfo',
payload: 'aaaaa',
});
}
// 同步調(diào)用
setDetail(){
const { dispatch } = props;
dispatch({
type: 'list/setDetail',
payload: 'bbb',
});
}
public render() {
// 從props中獲取
const { payInfo, detail } = this.props;
return (
<div >
{payInfo}
div>
);
}
}
export default PayInfo;
復(fù)制代碼
models
代碼:
import { setPayInfoRequest } from '@/services/list';
export default {
namespace: 'list',
state: {
payInfo:{},
detail:'',
},
effects: {
*setPayInfo({ payload }, { call, put }) {
const response = yield call(setPayInfoRequest, payload);
yield put({
type: 'setPayInfoReducers',
payload: {
res: response,
},
});
return response;
},
},
reducers: {
setDetail(state, { payload }) {
return {
...state,
detail:payload
};
},
setPayInfoReducers(state, { payload }) {
return {
...state,
payInfo: payload,
};
},
},
};
復(fù)制代碼
services
代碼:
export async function setPayInfoRequest(params) {
return request('/api/setPayInfo', {
method: 'POST',
body: {
...params
}
});
}
復(fù)制代碼
可以再對(duì)照?qǐng)D片整理一下思路,哈哈哈
相關(guān)案例查看更多
相關(guān)閱讀
- 云南小程序公司
- 云南小程序被騙蔣軍
- 網(wǎng)站排名優(yōu)化
- 云南小程序代建
- 貴州小程序開(kāi)發(fā)
- 網(wǎng)站建設(shè)費(fèi)用
- 云南小程序被騙
- painter
- 小程序表單
- 報(bào)廢車(chē)回收管理系統(tǒng)
- 云南軟件設(shè)計(jì)
- 云南小程序開(kāi)發(fā)課程
- 網(wǎng)站建設(shè)案例
- 云南網(wǎng)絡(luò)營(yíng)銷(xiāo)
- 網(wǎng)絡(luò)公司報(bào)價(jià)
- 網(wǎng)站建設(shè)報(bào)價(jià)
- 開(kāi)發(fā)微信小程序
- 日歷組件
- 云南網(wǎng)站建設(shè)高手
- 微分銷(xiāo)
- 搜索引擎排名
- 小程序制作
- 云南網(wǎng)站建設(shè)哪家公司好
- 小程序技術(shù)
- 汽車(chē)報(bào)廢軟件
- 軟件開(kāi)發(fā)
- 網(wǎng)站建設(shè)快速優(yōu)化
- 保山小程序開(kāi)發(fā)
- 昆明小程序代建
- 南通小程序制作公司