preface
I wrote a gadget back in Taro 0. X, although few people play it. Recently it happened that Taro 1.2.x has been released
React style applet framework, partial compromise for applet. Find something to test the waters and see how it improves.
Just the company has a need to do a mobile phone end of the report management procedures, the meeting pulled over;
In addition to basic React skills, you need to know both React and React.
- Small program own document:
Taro
Most of the components are packaged based on official apis - Support for Async await/special problem handling/best practices /Async await
Although this project (only wechat terminal) is not very big, there are still a lot of things to sort out, other nonsense not to say, straight to the theme
The problem summary
Life cycle andJSX
the{}
Arrow functions are not supported
[Fixed] Using arrow functions produces uncontrollable results.
The most common is error reporting;
JSX
It only supportsonClick={this.xxxx.bind(this,args)
This kind of writing- Life cycle use can lead to,
store
orrender
Abnormal results (such as execution order and value errors) - Other general functions support the arrow function notation
Dynamic style
Although Taro officially supports CSS Modules, if you’re considering multiple platforms.. It is recommended to maintain it with a regular naming scheme
As for the dynamic CSS class handling of classnames.. I prefer to use the Classnames library
Classname: The most common usage is as follows
// Taro is used in the same way as React. Taro should be placed in {}, otherwise an error will be reported (= classnames).
import classnames from 'classnames'
<View className={classnames({
"tab-operator": true."show": userIdList.length>0."hide": userIdList.length === 0})} ><View className="tab-content-top-counter">
<View className="left-text">{userIdList.length === 0 ? 'Please check the following items if you want to operate items! ': 'The ${useridlist. length} bar'} is selected.</View>
{userIdList.length === 0 ? null : <View className="unselect" onClick={this.unselect.bind(this)}>cancel</View>}
</View>
Copy the code
Missing tooltip type for its own wrapped component (TS)
For example, if you expose components that rely on components packaged by Taro,
The feature you added will be missing, causing the editor to display an error message.
The easiest way to do this is to use type or interface, so you don’t get an error. Such as the following
/ / way
type staticPropsSearchPanel={
open: boolean, onClose? :(a)= > void
}
// We can also use interface, which can inherit from other interfaces
2 / / way
interface staticPropsSearchPanel {
open: boolean, onClose? :(a)= > void
}
class SearchPanel extends Component<staticPropsSearchPanel>{}
Copy the code
Component support
-
Functional components are not supported: As of 1.2.x, there is no support for class XX extends Component
-
Multiple class XX extends references within the same file are not supported
How many state managers are allowed to access?
Dva, MOBx, and Redux all have corresponding taro access solutions. The latter two are officially maintained by Taro
Whether to supportalias
The latest version is supported (available) and exposes configuration files in the Config directory, although many other WebPack configurations also have some direct exposure
As for alias symbols that esLint does not recognize, there is no solution for this. I have tried some schemes in the community, and they don’t seem to work!
Precautions for route redirection
- Underlined pit jumps do not support underlined pit jumps (currently), unknown later
Development mode and real machine debugging can compile normally, package upload is not recognized… Waste a lot of my time..
- The pit of the path
The forward URL must be the full path!!!!! , such as
// Redirect, which provides a back button
Taro.redirectTo({ url: '/pages/list/index' })
Reload the entire program, close all other pages (the one that clears the stack), and then open the page you specify
// This is ideal when authentication fails or expires. Open only the registration page
Taro.reLaunch({ url:'/pages/login/index'})
// And any other 'navigate' items that taro encapsulates are generally written in wechat documents
Copy the code
Authentication page rendering obtrusive improves posture!
If you do an authentication jump on the first page, it’s very easy to get a jump on the render section
The visual feedback is not very good, for this, write an intermediate authentication page as the first page, the jump will improve a lot (visually)
Because the effects can be customized without rendering a lot of unnecessary components
For example, my entry page is Auth
import './index.less';
import { View } from '@tarojs/components';
import Taro, { Component, Config } from '@tarojs/taro';
class Auth extends Component {
/** * Specify config to be declared as: Taro.Config ** Since typescript can deduce only basic types of Key for object types * for things like navigationBarTextStyle: 'black' such a derived type is string * navigationBarTextStyle tips and statement: 'black' | 'white' type of conflict, the need to display the statement type * /
config: Config = {
navigationBarTitleText: 'Xx little Assistant'
}
static options = {
addGlobalClass: true
}
// If you have a token, you can enter the content area.
// No token to login
componentDidShow() {
const token = Taro.getStorageSync('token');
if(!!!!! token) { Taro.redirectTo({url: '/pages/list/index' })
return
}
Taro.redirectTo({ url: '/pages/login/index' })
}
render() {
return (
<View className='auth-page'>loading....</View>)}}export default Auth
Copy the code
componentDidShow
The attention of the points
PreviewImage (click on the full screen preview of the image), when closed will trigger the lifecycle again..
So putting the request here requires weighing up your own.. For example, after my list is expanded, clicking the picture to close will cause the list to brush again;
If YOU move it to componentWillMount, it’s not affected by the previewImage
mobx
Access and data observation?
Mobx access is almost the same as regular access and usage is almost the same..
From Mox-React to @tarojsw/mobx, provided by taro package
Devtools. Applets are currently only visible from developer tools,
It’s not as clear as professional DevTools, but you can see the organization and response of the data in general, as shown
In combination withmobx
Pre-request before jump?
For example, the detail page, the page showing the class, we usually use typeId to get the specific details, and then display
The normal thing to do is to go in and trigger the request in componentDidMount, and then render the result set to the page,
But if you go in and you show the default data and you replace it, it’s a little bit awkward; We definitely want to improve the user experience, so pre-request the data
We can start with the life cycle before the jump based on the actual scenario, for example redirecTo can call the function Dispatch within componentDidHide
ReLuanch can now trigger in componentWillUnmount.
Jump to the past page, you can get the render directly from props, it’s not so obtrusive
Timestamp and common date format conversion
For date processing, we most commonly use the time stamp for both postures and the more readable YYYY-MM-DD for presentation
So there’s no need to introduce the moment library. It’s a dayJS library. It’s a very small library.
- dayjs
Of course, you can also encapsulate a transformation with a function yourself, so you don’t need to introduce an additional library.
Note to obtain node information
To specify a node within the component itself,this must be this.$scope
This.$scope represents the component itself (instance) in taro.
componentDidMount() {
const query = Taro.createSelectorQuery().in(this.$scope);
query.select('#list-card').boundingClientRect((res) = > {
console.log('res: ', res);
}).exec()
}
Copy the code
Change the basic information of the project (wechat mini program)
Checking directly in the developer tools option will not be saved to the project, such as base library switch;
What works is to directly manipulate project. Config. json in the root directory
// The parameters of this configuration can be specified by wechat official explanation, which will be more comprehensive // https://developers.weixin.qq.com/miniprogram/dev/devtools/projectconfig.html?search-key=%E9%A1%B9%E7%9B%AE%E9%85%8D%E7%B D%AE {"miniprogramRoot": "Package output path"."projectname": "Project Name"."description": "Sound Management applet."."appid": "xxxx"."setting": {
"urlCheck": true, // Whether to check the secure domain name and TLS version"es6": false, // Whether to enable ES6 conversion"postcss": true// Enable postCSS support"minified": false// Whether to compress the code"newFeature": true// Enable new feature support},"compileType": "miniprogram"// Compile type"libVersion": "2.5.0"// Specify the base library version"condition": {}}Copy the code
Other applets have corresponding configuration files, see the official link
- Project configuration
It’s a package of little things
Request Encapsulation (TS)
request.tsx
- To support routing
prefix
header
The merger of- Response interception
- To support routing
/* * @author: CRPER * @lasteditors: CRPER * @github: https://github.com/crper * @motto: It is fun to be a hero. If you don't learn, you share. * @description: request interface encapsulation */
import Taro from '@tarojs/taro';
import '@tarojs/async-await';
interface options {
header: any, method? :string, dataType? :string, responseType? :string, success? :Function, fail? :Function, complete? :Function
}
/** ** @param URL: interface path * @param method: request method (RESTFUL, but PATCH is not available) * @param data: passed data * @param options: * @param prefix: The extra prefix of the interface */
export default async function(url: string, method? :string,data? :string | [any] | Object, options? : options, prefix? :string){
// Patch!!!!! is not supported Wechat's own request itself does not support patch!!
// wechat caches tokens by itself
const wxToken:string|void =await Taro.getStorage({ key: 'token' })
.then(res= > res.data).catch(err= > {
if(err) return})/ / the default value
const defaultOtions: options = {
method: 'GET',
header:{}
}
// If there is a token, grant it
if (wxToken) {
defaultOtions.header.Authorization = wxToken
}
const baseUrl: string = process.env.NODE_ENV === 'development' ? 'https://xxx.com/api/web' : 'https://xxx.com/api/web';
const newUrl = prefix ? `${baseUrl}${prefix}${url}` : `${baseUrl}${url}`
const requestObject: any= { url: newUrl, ... defaultOtions, ... options, method, data }const codeMessage: Object = {
200: 'The server successfully returned the requested data. '.201: 'Creating or modifying data succeeded. '.202: 'A request has been queued in the background (asynchronous task). '.204: 'Deleting data succeeded. '.400: The server did not create or modify data. '.401: 'User has no permissions (wrong token, username, password). '.403: 'The user is authorized, but access is forbidden. '.404: 'The request was made for a nonexistent record, and the server did not act on it. '.406: 'Requested format not available. '.410: 'The requested resource is permanently deleted and will not be retrieved. '.412: 'Access denied, please log in again'.422: 'A validation error occurred while creating an object. '.500: 'Server error, please check server. '.502: 'Gateway error. '.503: 'Service unavailable, server temporarily overloaded or maintained. '.504: 'Gateway timed out. '};// Check the request status
const checkStatusAndFilter = (response):Promise<any> | undefined= > {
if (response.statusCode >= 200 && response.statusCode < 300) {
if (response.statusCode === 200 || response.statusCode === 304) {
return response.data
}
return response;
}
// All other errors traversed above the error message throw an exception
const errortext = codeMessage[response.statusCode] || response.errMsg;
Taro.showToast({
title: errortext,
mask: true,
icon: 'none',
duration: 2000
})
return Promise.reject(response)
};
try {
return await Taro.request(requestObject)
.then(checkStatusAndFilter)
.then(res= > {
// This block is negotiated between me and the backend. If the internal interface is 1, the error occurs
if (res.code === 1) {
const errMsg = res.msg ? res.msg : 'Wrong interface';
Taro.showToast({
title: errMsg,
mask: true,
icon: 'none',
duration: 2000
})
Promise.reject(errMsg)
}
if (res.code === 0) {
if (res.data) {
return res.data
}
return null
}
return res
}).catch(errRes= > {
if (errRes.statusCode === 412) {
Taro.reLaunch({ url:'/pages/login/index'})}})}catch (err) {
Taro.showToast({
title: 'Code execution exception',
mask: true,
icon: 'none',
duration: 2000}}})Copy the code
- usage
// I configured the alias
import wxfetch from '@utils/request';
// For example, one of the requests in my code, processing behavior
// Cut the list data
spliceList = (dataIdArr: Array<string | number> = []) = > {
const {list, paginate: {total}} = this.state;
// If there is only one item, try the request list to see if there is any new data
if (list.length <= 1) {
this.getList()
}
let tempArr: Array<Object> = list.filter((item) = > {
for (let i = 0; i < dataIdArr.length; i++) {
let innerItemId = Number(dataIdArr[i]);
if(item.id ! == innerItemId) {return item
}
}
})
this.setState({
list: tempArr,
paginate: {
total: total - dataIdArr.length
},
dataIdArr: []})}// Handle behavior
handleActionSheetClick = async (e: number): Promise<any> => {
try {
const actionParam = {operationType: e};
const {dataIdArr, operationNote} = this.state;
constisActionNoValid: boolean = ! e || e ===0| | -Array.isArray(dataIdArr) && dataIdArr.length === 0);
if (isActionNoValid) {
Taro.atMessage({
'message': 'Please check again if your behavior is normal, such as check data! '.'type': 'error'.'duration': 1000
})
return false;
}
await wxfetch('/suspiciousDatas'.'POST', { dataIdArr, operationNote, ... actionParam });// Cut the array and close the mask layer
this.spliceList(dataIdArr);
this.handleActionSheetClose();
} catch (err) {
console.log(err); }}Copy the code
Simplified version of throttle (TS)
throttle.tsx
/* * @author: CRPER * @lasteditors: CRPER * @github: https://github.com/crper * @motto: It is fun to be a hero. If you don't learn, you share. * @description: simplified version of the throttle function */
/** * @param fn: callback function * @param threshold: time, in milliseconds */
export default function throttle(fn: Function, threshold: number = 1500) {
if (threshold === null) {
threshold = 1500
}
let _lastExecTime: null | number = null;
let context = this
return function (. args:any[]) :void {
let _nowTime: number = new Date().getTime();
if (_nowTime - Number(_lastExecTime) > threshold || ! _lastExecTime) { fn.apply(context, args); _lastExecTime = _nowTime } } }Copy the code
- usage
On the basis of this.xxx.bind
import throttle from '@utils/throttle';
// Scroll to the top to trigger
onScrolltoupper = throttle((a)= > {
console.log('1111');
},3000)
Copy the code
Drop-down refresh shows the built-inloading
.
Is wechat own three small points, this needs to configure some of the next page of its own properties.
Taro can declare page properties within a component simply by introducing Config
import Taro, { Component, Config } from '@tarojs/taro';
class ReportList extends Component {
/** * Specify config to be declared as: Taro.Config ** Since typescript can deduce only basic types of Key for object types * for things like navigationBarTextStyle: 'black' such a derived type is string * navigationBarTextStyle tips and statement: 'black' | 'white' type of conflict, the need to display the statement type * /
config: Config = {
navigationBarTitleText: 'Suspicious data Summary',
enablePullDownRefresh: true.// Enable the pull-down refresh feature
backgroundTextStyle: "dark".// Change the color of the displayed text to dark or light. You can't see the background because it's the same color
backgroundColor:'#f7f7f7' // The background color of the page}}// After enable, remember to add the corresponding condition to close, otherwise will always display
// Drop refresh
onPullDownRefresh = () :void= > {
// This loading is the navigation bar, the page title shows a loading, built-in wechat
Taro.showLoading({
title: 'loading.... '
})
// Since my interface requests are async await gestures, they can be queued
this.getList();
this.unselect();
// After the interface request is complete, hide two loading, title and drop down area
Taro.hideLoading();
Taro.stopPullDownRefresh();
}
Copy the code
Implement component style transitions?
Implementing a component transition enhances the experience to a certain extent, essentially CSS3 writes transitions,
For example, look at my side to achieve an effect, I feel still look past
- style
Animation-opacity: 0; // Animation-opacity: 0; // Animation-opacity: 0; The transform: translateY (100 vh) rotate (270 deg) scale (0.5); &.fadeIn{ opacity: 1; transform: translateY(0) rotate(0deg); The transition: all 0.3 s ease - in-out; } &.fadeOut{ opacity: 0; The transform: the rotate (270 deg) scale (0.2) translateX (- 100 vw); The transition: all 0.3 s ease - in-out; }}Copy the code
- Function area
We use classnames to dynamically append classes
<View className={classnames({ "search-panel": true, 'fadeIn': open, 'fadeOut': ! open})} > </View>Copy the code
Transition of node element height (CSS3)
It’s a transition between unfolding and folding,
After N attempts (cannot set height to element!!) Max-height :0,
Other transitions can be resolved by setting the appropriate max-height
Support in the face of events in Taro
Some documents did not say, can only go to the source… See common.d.ts for obvious reasons, such as long press events
Github.com/NervJS/taro…
CSS 3 loading is introduced into
In fact, with the common development mode on the writing method is not bad, basic or CSS3 function,DIV can be identified by the node only.. Such as Taro
// Style section
.no-data-text {
background-color: rgba(233.228.228.0.726);
color: # 333;
height: 100vh;
width: 100%;
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
font-size: 50px;
font-weight: 700;
.loading-text{
font-size:28px;
color:# 555; }}.spinner {
width: 200px;
height: 70px;
text-align: center;
font-size: 10px;
}
.spinner .rect {
background-color: rgb(123.176.225);
height: 100%;
width: 10px;
margin:0 5px;
display: inline-block;
-webkit-animation: stretchdelay 1.2 s infinite ease-in-out;
animation: stretchdelay 1.2 s infinite ease-in-out;
}
.spinner .rect2 {
-webkit-animation-delay: -1.1 s;
animation-delay: -1.1 s;
}
.spinner .rect3 {
-webkit-animation-delay: -1.0 s;
animation-delay: -1.0 s;
}
.spinner .rect4 {
-webkit-animation-delay: -0.9 s;
animation-delay: -0.9 s;
}
.spinner .rect5 {
-webkit-animation-delay: -0.8 s;
animation-delay: -0.8 s;
}
@-webkit-keyframes stretchdelay {
0%.40%.100% { -webkit-transform: scaleY(0.4)}20% { -webkit-transform: scaleY(1.0)}}@keyframes stretchdelay {
0%.40%.100% {
transform: scaleY(0.4);
-webkit-transform: scaleY(0.4);
} 20% {
transform: scaleY(1.0);
-webkit-transform: scaleY(1.0); }}Copy the code
<! -- Node part -->
<View className="no-data-text">
<View className="spinner">
<View className="rect rect1"></View>
<View className="rect rect2"></View>
<View className="rect rect3"></View>
<View className="rect rect4"></View>
<View className="rect rect5"></View>
</View>
<View className="loading-text">Loading......</View>
</View>
Copy the code
conclusion
By the time this article is output,Taro’s version
👽 Taro v1.2.7 Taro CLI 1.2.7 Environment Info: System: OS: macOS 10.14.2 Shell: 5.3 - /bin/zsh Binaries: Node: 10.14.2 - / usr /local/bin/node
Yarn: 1.13.0 - /usr/local/bin/yarn
npm: 6.5.0 - /usr/local/bin/npm npmPackages: @tarojs/async-await: 1.2.7 => 1.2.7 @tarojs/components: 1.2.7 => 1.2.7 @tarojs/mobx: 1.2.7 => 1.2.7 @tarojs/ mobx-h5:1.2.7 => 1.2.7 @tarojs/ mobx-RN: 1.2.7 => 1.2.7 @tarojs/plugin-babel: 1.2.7 => 1.2.7@tarojs /plugin-csso: 1.2.7 => 1.2.7@tarojs /plugin-less: 1.2.7 => 1.2.7@tarojs /plugin-sass: 1.2.7 => 1.2.7@tarojs /plugin-uglifyjs: 1.2.7 => 1.2.7@tarojs/Rn-runner: 1.2.7 => 1.2.7@tarojs /router: 1.2.7 => 1.2.7 @tarojs/taro: 1.2.7 => 1.2.7 @tarojs/taro-h5: 1.2.7 => 1.2.7 @tarojs/taro-h5: 1.2.7 => 1.2.7@tarojs /taro-swan: 1.2.7 => 1.2.7@tarojs/taro-TT: 1.2.7 => 1.2.7@tarojs/taro-appellate: 1.2.7 => 1.2.7@tarojs/webpack-Runner: 1.2.7 => 1.2.7 ESlint-config-taro: 1.2.7 => 1.2.7 eslint-plugin-taro: 1.2.7 = > 1.2.7Copy the code
The current version of Taro and THE Taro UI still needs to be improved to support TS, and will occasionally encounter a lack of types
If the project is not big, for those who want to save worry, it is recommended to directly masturbate JS version;
The Taro community is still very active, and as such, two or three iterations of X.Y.Z(y-bit) should be useful.
The benefits of TS are obvious. The editor can float inferred types directly, and many errors can be avoided during development.
This is the end of hydrology, there is something wrong please leave a message, will be timely correction, thank you for reading.