手摸手教你使用 Taro+dva+Hooks快速開(kāi)發(fā)小程序

最近在研究小程序這方面的東西菊霜,使用到了京東基于 React 的小程序開(kāi)發(fā)框架 Taro ,相比 mpvueuni-app 這兩個(gè)框架來(lái)說(shuō)脊另,Taro 顯得更優(yōu)雅导狡,更穩(wěn)重,大廠在迭代偎痛,就是不一樣旱捧,一句話(huà) ,就是坑少一點(diǎn)~

前置知識(shí)

看本篇教程前需要你掌握 dva ,React Hooks ,Redux ,還有小程序的開(kāi)發(fā)流程看彼。希望你知其然廊佩,并知其所以然。如果你不具備以上任意一點(diǎn)靖榕,建議先停下來(lái)标锄,下面我給出地址,先自行學(xué)習(xí)之后再過(guò)來(lái)看我這篇文章 茁计。

Redux-React全局狀態(tài)管理工具之一

dva-讓你的全局狀態(tài)管理更簡(jiǎn)單

React-用于構(gòu)建用戶(hù)界面的 JavaScript 庫(kù)

React Hooks-更優(yōu)雅的React應(yīng)用書(shū)寫(xiě)方式

小程序

Taro-基于React的小程序框架


正式開(kāi)始

安裝 Taro腳手架

# 使用 npm 安裝 CLI
$ npm install -g @tarojs/cli
# OR 使用 yarn 安裝 CLI
$ yarn global add @tarojs/cli
# OR 安裝了 cnpm料皇,使用 cnpm 安裝 CLI
$ cnpm install -g @tarojs/cli

因?yàn)槲译娔X安裝了 cnpm 鏡像源,所以下文我都會(huì)用 cnpm

腳手架完成后使用腳手架初始化一個(gè)新項(xiàng)目

在你需要建立項(xiàng)目的文件夾打開(kāi) CMD

taro init test//我們演示的項(xiàng)目名叫test

然后跟著流程走星压,這邊為了減少你的學(xué)習(xí)成本践剂,建議不要選擇 Typescript ,css選擇less,模版選擇默認(rèn)模版。

image

最后成功之后娜膘,用你的編輯器打開(kāi)test目錄逊脯。

你的目錄結(jié)構(gòu)跟我的應(yīng)該是一樣的

image

先刪除 ./src/pages 下面的 index 文件夾。

然后命令行在test 目錄打開(kāi)竣贪,安裝我們需要用的擴(kuò)展

cnpm install --save @tarojs/async-await  //沒(méi)想到吧 在Taro里面使用 async和 await 需要安裝這個(gè)擴(kuò)展
cnpm install --save redux @tarojs/redux @tarojs/redux-h5 redux-thunk redux-logger //Redux全家桶
cnpm install --save dva-core dva-loading  //dva
cnpm install --save taro-axios //在Taro里面使用axios 需要安裝他

這四個(gè)命令安裝完之后军洼,打開(kāi)./src 目錄 ,新建兩個(gè)文件夾 演怎,一個(gè)叫 utils 一個(gè)叫 models 注意這兩個(gè)文件夾應(yīng)該跟你的 pages 文件夾同級(jí)匕争。

utils 文件夾下面新建文件 dva.js 寫(xiě)上下面的內(nèi)容 注冊(cè)dva

import { create } from 'dva-core';
import { createLogger } from 'redux-logger';
import createLoading from 'dva-loading';
let app;
let store;
let dispatch;

function createApp(opt) {
  // redux日志
  // opt.onAction = [createLogger()];
  app = create(opt);
  app.use(createLoading({}));

  if (!global.registered) opt.models.forEach(model => app.model(model));
  global.registered = true;
  app.start();

  store = app._store;
  app.getStore = () => store;

  dispatch = store.dispatch;

  app.dispatch = dispatch;
  return app;
}
export default {
  createApp,
  getDispatch() {
    return app.dispatch;
  }
}

utils 文件夾下面新建文件 request.js 寫(xiě)上下面的內(nèi)容 封裝一個(gè)簡(jiǎn)單的axios 實(shí)際你的項(xiàng)目中可能不一樣

import axios from "taro-axios";
const baseURL = `https://blog.xiaohuwei.cn`
const service = axios.create({
    baseURL: baseURL,
    withCredentials: true, 
    timeout: 300000
});
service.interceptors.response.use(
    response => {
        return response.data;
    },
    error => {
        return Promise.reject(error)
    })

export default service

models 文件夾下面新建文件 models.js 寫(xiě)上下面的內(nèi)容 連接你每個(gè)頁(yè)面的倉(cāng)庫(kù)注冊(cè)到全局

import index from '../pages/index/model';

export default [index];

你會(huì)發(fā)現(xiàn)我們剛才吧 index 文件夾已經(jīng)刪除了 ,這里先這樣寫(xiě)爷耀,后面我在做說(shuō)明甘桑。

下一步 修改 ./src/app.jsx 作用就是把我們所有的倉(cāng)庫(kù)連接進(jìn)來(lái) 方便你學(xué)習(xí) 下面給出修改后的全部代碼

import '@tarojs/async-await'
import Taro, { Component } from '@tarojs/taro'
import Index from './pages/index'
import dva from './utils/dva';
import models from './models/models';
import { Provider } from '@tarojs/redux';
import './app.less'
const dvaApp = dva.createApp({
  initialState: {},
  models: models,
});
const store = dvaApp.getStore();
class App extends Component {
  config = {
    pages: [
      'pages/index/index'
    ],
    window: {
      backgroundTextStyle: 'light',
      navigationBarBackgroundColor: '#fff',
      navigationBarTitleText: 'WeChat',
      navigationBarTextStyle: 'black'
    }
  }
  componentDidMount() { }
  componentDidShow() { }
  componentDidHide() { }
  componentDidCatchError() { }
  // 在 App 類(lèi)中的 render() 函數(shù)沒(méi)有實(shí)際作用
  // 請(qǐng)勿修改此函數(shù)
  render() {
    return (
      <Provider store={store}>
        <Index />
      </Provider>

    )
  }
}
Taro.render(<App />, document.getElementById('app'))

最后一步

在你項(xiàng)目 根目錄 ,為了跟我保持一致,希望你在根目錄新建一個(gè)叫 page.js的文件 這個(gè)文件我們用來(lái)自動(dòng)生成新頁(yè)面跑杭,包含新頁(yè)面的 ui層 service層model層方便快速開(kāi)發(fā)铆帽。內(nèi)容如下

/**
 * pages模版快速生成腳本,執(zhí)行命令 npm run temp `文件名`
 */
const fs = require('fs');
const dirName = process.argv[2];
if (!dirName) {
  console.log('文件夾名稱(chēng)不能為空!');
  console.log('示例:npm run temp test');
  process.exit(0);
}
// 頁(yè)面模版
const indexTep = `import Taro,{useEffect} from '@tarojs/taro';
import { View,Text } from '@tarojs/components';
import { connect } from '@tarojs/redux';
import './index.less';

const ${titleCase(dirName)} = props =>{
    const {${dirName},loading} = props;
      useEffect(() => {
        console.log(props)
      }, [])
    return (
           <View className="${dirName}-page">
             <Text>正如你所見(jiàn)這是你的${dirName}頁(yè)面</Text>
           </View>
           )
}
${titleCase(dirName)}.config = {
  navigationBarTitleText: '${dirName}'
}
//全局樣式繼承 你可以關(guān)掉
${titleCase(dirName)}.options = {
  addGlobalClass: true
}
export default connect(
    ({
    ${dirName},
    loading
    })=>({
    ${dirName},
    loading
}))(${titleCase(dirName)})
`;
// less文件模版
const lessTep = `

.${dirName}-page {
}
`;

// model文件模版
const modelTep = `import * as ${dirName}Api from './service';

export default {
  namespace: '${dirName}',
  state: {
      keai:'測(cè)試數(shù)據(jù)666'
  },

  effects: {
    * effectsDemo(_, { call, put }) {
      const { status, data } = yield call(${dirName}Api.demo, {});
      if (status === 'ok') {
        yield put({ type: 'save',
          payload: {
            topData: data,
          } });
      }
    },
  },

  reducers: {
    save(state, { payload }) {
      return { ...state, ...payload };
    },
  },

};
`;


// service頁(yè)面模版
const serviceTep = `import Request from '../../utils/request';

export const demo = (data) => {
  return Request({
    url: '路徑',
    method: 'POST',
    data,
  });
};
`;
fs.mkdirSync(`./src/pages/${dirName}`); // mkdir $1
process.chdir(`./src/pages/${dirName}`); // cd $1

fs.writeFileSync('index.js', indexTep);
fs.writeFileSync('index.less', lessTep);
fs.writeFileSync('model.js', modelTep);
fs.writeFileSync('service.js', serviceTep);
console.log(`模版${dirName}已創(chuàng)建,請(qǐng)手動(dòng)按照格式增加到./src/models`);
function titleCase(str) {
  const array = str.toLowerCase().split(' ');
  for (let i = 0; i < array.length; i++) {
    array[i] = array[i][0].toUpperCase() + array[i].substring(1, array[i].length);
  }
  const string = array.join(' ');
  return string;
}
process.exit(0);

完成之后 去 package.json 里面的 scripts 添加一條 命令 "temp": "node page.js"


如果你能夠走到這一步 德谅,說(shuō)明你已經(jīng)成功了 锄贼,跟我的目錄結(jié)構(gòu) 對(duì)照一下

image

命令行在你的項(xiàng)目目錄打開(kāi),我們來(lái)使用 腳本生成第一個(gè)頁(yè)面 index

npm run temp index

你會(huì)發(fā)現(xiàn)你的./src/pages 目錄下多了 index 文件夾 并且文件夾下面已經(jīng)為你初始化好了所有你需要的文件女阀,但是并沒(méi)有結(jié)束宅荤。

就是上文提到的 ,每次新建一個(gè)頁(yè)面都需要去 ./src/models/models.js 手動(dòng) 按照我給你的格式引入一次浸策,因?yàn)槲疫@個(gè)組件叫 index冯键,所以我給你的默認(rèn)就是 index,所以我這里不用改,你做項(xiàng)目的時(shí)候庸汗,是需要手動(dòng)加的惫确。

試試效果!

npm run dev:weapp
image

好啦蚯舱,所有的都完成啦改化,開(kāi)始開(kāi)發(fā)你的小程序吧!~


說(shuō)下 Taro的注意事項(xiàng)

當(dāng)你 使用到了 圖片這些靜態(tài)資源的時(shí)候 枉昏,需要使用 import 的語(yǔ)法引用陈肛。

如果你想看完整代碼 移步

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市兄裂,隨后出現(xiàn)的幾起案子句旱,更是在濱河造成了極大的恐慌,老刑警劉巖晰奖,帶你破解...
    沈念sama閱讀 206,968評(píng)論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件谈撒,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡匾南,警方通過(guò)查閱死者的電腦和手機(jī)啃匿,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,601評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)蛆楞,“玉大人溯乒,你說(shuō)我怎么就攤上這事‰叮” “怎么了橙数?”我有些...
    開(kāi)封第一講書(shū)人閱讀 153,220評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵尊流,是天一觀的道長(zhǎng)帅戒。 經(jīng)常有香客問(wèn)我,道長(zhǎng),這世上最難降的妖魔是什么逻住? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,416評(píng)論 1 279
  • 正文 為了忘掉前任钟哥,我火速辦了婚禮,結(jié)果婚禮上瞎访,老公的妹妹穿的比我還像新娘腻贰。我一直安慰自己,他們只是感情好扒秸,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,425評(píng)論 5 374
  • 文/花漫 我一把揭開(kāi)白布播演。 她就那樣靜靜地躺著,像睡著了一般伴奥。 火紅的嫁衣襯著肌膚如雪写烤。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 49,144評(píng)論 1 285
  • 那天拾徙,我揣著相機(jī)與錄音洲炊,去河邊找鬼。 笑死尼啡,一個(gè)胖子當(dāng)著我的面吹牛暂衡,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播崖瞭,決...
    沈念sama閱讀 38,432評(píng)論 3 401
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼狂巢,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了书聚?” 一聲冷哼從身側(cè)響起隧膘,我...
    開(kāi)封第一講書(shū)人閱讀 37,088評(píng)論 0 261
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎寺惫,沒(méi)想到半個(gè)月后疹吃,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,586評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡西雀,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,028評(píng)論 2 325
  • 正文 我和宋清朗相戀三年萨驶,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片艇肴。...
    茶點(diǎn)故事閱讀 38,137評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡腔呜,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出再悼,到底是詐尸還是另有隱情核畴,我是刑警寧澤,帶...
    沈念sama閱讀 33,783評(píng)論 4 324
  • 正文 年R本政府宣布冲九,位于F島的核電站谤草,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜丑孩,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,343評(píng)論 3 307
  • 文/蒙蒙 一冀宴、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧温学,春花似錦略贮、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,333評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至轧拄,卻和暖如春真友,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背紧帕。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,559評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工盔然, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人是嗜。 一個(gè)月前我還...
    沈念sama閱讀 45,595評(píng)論 2 355
  • 正文 我出身青樓愈案,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親鹅搪。 傳聞我的和親對(duì)象是個(gè)殘疾皇子站绪,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,901評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容