Taro climb pit blood and tears history

Introduce a,

  • Taro is an open cross-end cross-framework solution that supports the use of React/Vue/Nerv frameworks to develop wechat/JD.com/Baidu/Alipay/Bytedance/QQ mini program/H5 and other applications. Now at the top of the market form is varied, the Web, the React Native, WeChat small programs and other side, when the business requirements in different side are required to show at the same time, more than to write code for different end cost is very high, obviously at that time only a set of code can be adapted to varying ability is very need.
  • Taro 2.X Supports React
  • Taro 3.0 supports VUE/VUE 3

Second, the installation

#Use NPM to install the CLI
$ npm install -g @tarojs/cli
#Create a template project using the command
$ taro init myApp
#Install dependencies
$ npm install
Copy the code

Note: The dependent version remains the same ++

Compile and package

"scripts": {
    "build:weapp": "taro build --type weapp"./ / WeChat
    "build:swan": "taro build --type swan"./ / baidu
    "build:alipay": "taro build --type alipay"./ / ali.
    "build:tt": "taro build --type tt"./ / byte
    "build:h5": "taro build --type h5".//H5
    "build:qq": "taro build --type qq".//qq
    "build:quickapp": "taro build --type quickapp"."dev:weapp": "npm run build:weapp -- --watch"."dev:nopre:weapp": "set NODE_ENV=devNoPre && npm run build:weapp -- --watch"."dev:swan": "npm run build:swan -- --watch"."dev:alipay": "npm run build:alipay -- --watch"."dev:tt": "npm run build:tt -- --watch"."dev:h5": "npm run build:h5 -- --watch"."dev:rn": "npm run build:rn -- --watch"."dev:qq": "npm run build:qq -- --watch"."dev:quickapp": "npm run build:quickapp -- --watch"."lint-staged": "lint-staged"
  },
Copy the code

4. Project directory structure

├ ─ ─ dist directory compiled results ├ ─ ─ the config configuration directory | ├ ─ ─ dev. The development of a js configuration | ├ ─ ─ index. The default configuration | js └ ─ ─ the prod. Js packaging configuration ├ ─ ─ the SRC source directory | ├ ─ ─ pages Page file directory | | ├ ─ ─ index index page directory | | | ├ ─ ─ index. The js index page logic | | | └ ─ ─ index. The CSS style index page | ├ ─ ─ app. The CSS style of total project general | └ ─ ─ ├ ── package.json app.js project entry fileCopy the code

Five, multi-terminal compilation

let pages = []
if (process.env.TARO_ENV === 'weapp') {
  pages = [
    '/pages/index/index']}if (process.env.TARO_ENV === 'swan') {
  pages = [
    '/pages/indexswan/indexswan']}export default {
  pages
}
Copy the code

6. Unit transformation

Small program, H5 size unit unified

  • Replace RPX with px
  • Run Dev :h5 automatically compiles to REM units (inline styles cannot be converted automatically, some TARo-UI SCSS cannot be converted automatically, need to be manually adjusted, reason unknown)
/config/index.js
const config = {
  projectName: 'myProject'.date: '2018-4-18'.designWidth: 640. }Copy the code

Seven, optimization

1. The subcontract

config:[
    pages:[],
    subpages:[]
]
Copy the code

2. The pre-rendered

  • The state of the page initialization is rendered directly to WXML as dataless, performing the rendering process before the framework and business logic run. An initial rendering of a Prerender page is usually as fast or faster than a native applet.
const config = {
  ...
  mini: {
    prerender: {
      match: 'pages/shop/**'.// All pages starting with 'pages/shop/' participate prerender
      include: ['pages/any/way/index'].// 'pages/any/way/index' also participate in prerender
      exclude: ['pages/shop/index/index'] // 'pages/shop/index/index' does not participate prerender}}};module.exports = config
Copy the code

3. Long list rendering

  • Render only views of the visible viewport
<VirtualList
    height= {500} /* List height */
    width= '100%' /* List width */
    itemData={data} /* Render list data */
    itemCount={dataLen} /* Render list length */
    itemSize={100} /* List item height */
>
    {Row} /* List single component, only one component can be passed in */
</VirtualList>
Copy the code

Eight, technical selection

React, Typescript, Mobx, Hooks

Nine, small program

1. The third-party H5 page is redirected

  • You need to configure the third-party HTTPS certificate, add a service domain name verification file to the third-party server, and configure the service domain name on the applet background. For details, see applet background Development configuration

2. Input lag problem

Quick input or quick deletion of data in the input box is stalled

  • Bind the old value, listen to the onChange event to set the copy value of the old value, == avoid component dependent value update ==
const [formData, setFormData] = useState(initState)
const [selfFormState, setSelfFormState] = useState(initState)
const handleChange = (type, value) = > {
    constnewState = { ... selfFormState, [type]: value, } setSelfFormState(newState)// Applets need return value
      return value
}
Copy the code
<AtInput
  name='name'
  title='name'
  type='text'
  required
  disabled
  placeholder='Please enter a name'
  value={formData.name}
  onChange={(val)= > {
    handleChange('name', val)
  }}
/>
Copy the code

3. TextArea has the highest level and involves popover coverage

Strange phenomenon of popover blocked by textArea

  • Controls display hiding of textArea
<View>
  <AtForm onSubmit={onSubmit}>
    <View>
      <View style={{ visibility: show ? 'hidden' : 'visible' }}>
        <AtTextarea
          count={false}
          value={formData.tel}
          onChange={(val)= >{handleChange('tel', val)}} maxLength={1000} placeholder={</View>
    </View>
  </AtForm>
  {show && (
    <View>Popup window content</View>
  )}
</View> 
Copy the code

4. Small program backward page refresh problem

For example, when you enter the edit page from the details page and return after editing, the applet will not request new data again. If you move forward, you get to the page stack maximum

  • The page returned by the applet triggers ==useDidshow==
function Index () {
  useDidShow(() = > {
    // Verify user status
  })

  return (
    <View>test</View>)}Copy the code

5. When the popover opens, fix the background hide background scrollbar

  • Add CSS to background when popover opens, hide scrollbar
.at-modal__content {
  overflow-y: hidden;
  ::-webkit-scrollbar{
    width: 0;
    height: 0;
    color: transparent; }}Copy the code

6. Obtain user data

Authorization operation popup window, the first rejection will not pop up again

  • It is recommended to use open components ==openData== to display the user profile picture and nickname if not necessary
<OpenData type='userAvatarUrl'/>
Copy the code

Ten, H5

1.Taro. Request ()H5 does not return data

  • Rewrap it with Axios
export function generateTaroReq (config) {
  return async(data? : AjaxData) => {const res = awaitTaro.request({ ... config, data, })const { data: resData } = res
    return resData.data
  }
}
Copy the code
export function generateTaroReq(axiosConfig:axiosConfig,config? :any) :Function{
  const dataName = axiosConfig.method&&axiosConfig.method.toLowerCase() == 'post' ? 'data' : 'params'
  return (data? :Object) = >{
    return axios({
      method:axiosConfig.method,
      url:'/xxxx/'+axiosConfig.url, [dataName]:{ ... data } }).then(res= > {
      return res.data
    })
  }
}

const reqBankInfo = generateTaroReq({
  url: 'xxxxx/api'.method: 'POST'
})
reqBankInfo(_ajaxData)
Copy the code

2. Login Taro. Login () is not available

H5 cannot be called

  • Replace it with another login form

3. Position: ScrollView cannot be rolled in the fixed state

The top tabs cannot be swiped left or right outside the width of the screen

  • If scrolling left and right is fixed in the header navigation menu, CSS properties (left and right) need to be set.
.className{
    position:fixed;
    top:0;
    left:0;
    right:0;
}
Copy the code

4.Taro.uploadFile()

  • The H5 end needs to add another parameter: fileName:’ XXXX.png ‘. An error occurs if no interface is added
const config = {
  url: '/xxxxx/uploadxImage'.// Upload interface
  filePath: path,
  name: 'file'.fileName:'file.' + type,
  header: {
    Authorization: Taro.getStorageSync('token'),
  },
}
Taro.uploadFile(config)
Copy the code

5. An error occurs during the tabs switch

Failed to execute ‘replaceChild’ on ‘Node’: The node to be replaced is not a child of this node.

  • The reason is that we use the same set of data, just separate list and showData
<AtTabs current={current} tabList={tabList} onClick={handleClick}>
    <AtTabsPane current={current} index={0}>
      <View key="0">{ showData&&! loading? ( view.map(item => { return<JinrongItem item={item}></JinrongItem>
          })):empty
        }
      </View>
    </AtTabsPane>
</AtTabs>
Copy the code

Change the = = = =

<AtTabs current={current} tabList={tabList} onClick={handleClick}>
    <AtTabsPane current={current} index={0}>
      <View key="0">{showData&&! loading? ( list.map((item, i) => { return<JirongItem value={item}></JirongItem>
          })):empty
        }
      </View>
    </AtTabsPane>
    <AtTabsPane current={current} index={1}>
      <View key="1">{showData2&&! loading? ( list2.map((item, i) => { return<XuqiuLow xuqiukey={_keys[current]} key={item.id} isedit value={item}></XuqiuLow>
          })):empty
        }
      </View>
    </AtTabsPane>
</AtTabs>
Copy the code

Tar.getcurrentpages () behaves differently in H5 and applet

  • H5 has no setData method

7. Picker component

The onChange hook, which selects the subscript method

  • Const value = event.detail.value[0]
  • H5: const value = event.detail.value

8. Replace the Editor component with zx-Editor

9. The value bound to the Testarea component cannot be null; otherwise, a Length of NULL error will be reported

<AtTextarea
    className="AtTextareaFix"
    count={false}
    value={textareaProps.value}
    onChange={textareaProps.onChange}
    maxLength={textareaProps.maxLength}
    placeholder={textareaProps.placeholder}
/>
Copy the code

10. The latest JS file cannot be obtained after the wechat browser project is updated

h5: {
    publicPath: '/'.output: {
      filename: 'js/[name].[hash].js'.chunkFilename: 'js/[name].[chunkhash].js'
    },
    miniCssExtractPluginOption: {
      filename: 'css/[name].[hash].css'.chunkFilename: 'css/[name].[chunkhash].css',}}Copy the code