欧美三级国产三级日韩三级_亚洲熟妇丰满大屁股熟妇_欧美亚洲成人一区二区三区_国产精品久久久久久模特

微信H5 React + Umi 開(kāi)發(fā)實(shí)踐總結(jié) - 新聞資訊 - 云南小程序開(kāi)發(fā)|云南軟件開(kāi)發(fā)|云南網(wǎng)站建設(shè)-昆明葵宇信息科技有限公司

159-8711-8523

云南網(wǎng)建設(shè)/小程序開(kāi)發(fā)/軟件開(kāi)發(fā)

知識(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)

正文

  1. 區(qū)分Umi與Dva

  2. Umi配置

  3. React常用寫(xiě)法

  4. Dva使用入門(mén)

  5. 微信配置

  6. TypeScript組件

  7. H5小技巧

  8. 日志記錄

  9. 其他


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)資源地址
Maserbuild:test測(cè)試fat.*.comcdn.fat.*.com
Developbuild:prod正式*.comcdn.*.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中可以使用watchapi方便的監(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ì)InputonChage事件增加防抖,借助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ě)下如何在不懂reduxredux-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)求

  1. 我們把models當(dāng)做一個(gè)全局變量,可以存放數(shù)據(jù),可以被任何頁(yè)面獲取,存和取都有對(duì)應(yīng)的Api。
  2. 存數(shù)據(jù)有2中方式,一種是直接把數(shù)據(jù)存到models里(同步請(qǐng)求),另一種是發(fā)一個(gè)請(qǐng)求然后把數(shù)據(jù)存到models里(異步請(qǐng)求)。
  3. 同步請(qǐng)求即reducers里的方法,會(huì)修改models.state里的數(shù)據(jù)。
  4. 異步請(qǐng)求即調(diào)用modelseffects方法,該方法會(huì)調(diào)用services方法獲取請(qǐng)求數(shù)據(jù)。
  5. 異步請(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)案例查看更多