成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

我在使用React Native/Redux開發中犯過的11個錯誤

開發 前端
在使用React Native近一年之后,是時候分享一下我剛開始用RN開發項目時犯過的錯誤了。有可能你對第一個React Native(RN)應用程序的預估是完全錯誤的!

在使用React Native近一年之后,是時候分享一下我剛開始用RN開發項目時犯過的錯誤了。

1.錯誤的估計

有可能你對***個React Native(RN)應用程序的預估是完全錯誤的!

  • 1)你需要分別考慮iOS和Android版本的布局!在布局的時候,有很多組件可以重復使用;如果ios和Android的頁面結構不同,就需要對他們分開單獨布局。
  • 2)對form進行評估時,***也考慮一下數據層驗證。
  • 3)了解數據庫結構,有助于正確地規劃redux

2.盡量使用基礎組件(buttons,footers,headers,inputs,texts)

google搜索RN的基礎組件,你會發現有很多現有組件可以方便的用到項目中,如buttons,footers等。如果項目中沒有特別的布局設計,只需要使用這些基礎組件就可以構建一個頁面。如果有一些特殊的設計,例如,特殊的button樣式,你就需要為每個按鈕設置自定義樣式。你可以封裝已經構建好的組件,并為它們定制樣式。但是我覺得使用View,Text,TouchableOpacity和RN的其他組件來構建自己的組件更加有意義。因為你會有更多的rn實踐,并且深刻理解如何使用RN。最重要的一點,你可以確定你自己構建的組件版本不會被改變。

3.不要把iOS和Android的布局分開

如果iOS和Android布局大致一樣,只有一小部分不同,你可以簡單地使用RN提供的Platform API根據設備平臺進行區分。

如果布局完全不同 – ***分散在不同的文件中單獨布局。

如果你給一個文件命名為index.ios.js – 程序打包時,在iOS中將使用這個文件顯示iOS布局。 index.android.js也是一樣的道理。

你可能會問:“代碼怎么復用呢?” 你可以將重復的代碼移動到助手函數中。需要的時候只復用這些助手函數。

4.錯誤的redux store規劃。

初學者經常會犯的一個很大的錯誤就是,當你在規劃你的應用程序時,你可能會考慮很多布局相關的問題,卻很少考慮關于數據的處理。

Redux能夠幫助我們正確地存儲數據。如果redux規劃的好 – 它將是管理應用程序數據的強大工具。

當我剛剛開始構建RN應用程序時,我曾考慮將reducers作為每個container的數據存儲。所以,如果你有登錄,忘記密碼,待辦事項列表頁面 – 使用他們的縮寫比較簡單:SignIn, Forgot, ToDoList.

在進行了一段工作后,我發現管理數據沒有想象中的容易。

當我從ToDo列表中選擇項目時 – 我需要將數據傳遞給ToDoDetails reducer。這意味著使用了額外的操作來發送數據到reducer。

在做了一些調查之后,我決定以不同的方式規劃結構。一個例子:

  1. Auth
  2. Todos
  3. Friends

Auth用于存儲認證的token。

而ToDos和Friends reducers用于存儲實體,當我去ToDo Detail頁面時 – 我只需要通過ID搜索所有的ToDos。

對于更復雜的結構,我推薦使用這種規劃,你可以快速的定位到你想找到的。

5.錯誤的項目結構

作為初學者時,總是規劃不好項目結構。

首先 ,需要分析你的項目是不是足夠大?

你的應用程序中有多少個頁面? 20?30?10?5?還是只有一個”Hello World”頁面?

我遇到并開始實施的***個結構是這樣的:

 

圖0:[外文翻譯]我在使用React Native / Redux開發中犯過的11個錯誤

如果你的項目不超過10個頁面,使用上面這種結構是沒有問題的。但是如果項目特別大 – 你可以考慮這樣規劃結構:

 

圖1:[外文翻譯]我在使用React Native / Redux開發中犯過的11個錯誤

區別在于,***種類型建議我們將actions和reducers與container分開存儲。第二種- 把它們存儲在一起。如果應用程序很小 – 將redux模塊從container中分離出來會更加有用。

如果你有通用的樣式(如Header、Footer、Buttons) – 你可以單***建一個名為“styles”的文件夾,在那里設置一個index.js文件并在其中寫入通用樣式。然后在每個頁面上重復使用它們。

實際項目中會有很多不同的結構。你應該了解使用哪種結構更適合你的需求。

6.錯誤的container結構。沒有從一開始就使用smart/dumb組件

當你開始使用RN并初始化項目時,index.ios.js文件中已經有一些代碼,存儲在一個單獨的對象中。

在實際開發項目中,你將需要使用很多組件,不僅僅是由RN提供的,還有自己構建的一些組件。構建container時,可以重用它們。

考慮該組件:

 

  1. import React, { Component } from ‘react’; 
  2. import { 
  3.    Text, 
  4.    TextInput, 
  5.    View
  6.    TouchableOpacity 
  7. from ‘react-native’; 
  8. import styles from ‘./styles.ios’; 
  9.  
  10. export default class SomeContainer extends Component { 
  11.    constructor(props){ 
  12.        super(props);        
  13.        this.state = { 
  14.            username:null 
  15.        } 
  16.    } 
  17.    _usernameChanged(event){        
  18.        this.setState({ 
  19.            username:event.nativeEvent.text 
  20.        }); 
  21.     } 
  22.    _submit(){        
  23.        if(this.state.username){            
  24.            console.log(`Hello, ${this.state.username}!`); 
  25.        }        
  26.        else{            
  27.            console.log(‘Please, enter username’); 
  28.        } 
  29.     } 
  30.                 
  31.     render() {         
  32.       return (             
  33.         <View style={styles.container}>             
  34.             <View style={styles.avatarBlock}>                 
  35.                 <Image 
  36.                         source={this.props.image}  
  37.                         style={styles.avatar}/>             
  38.             </View>             
  39.             <View style={styles.form}> 
  40.                 <View style={styles.formItem}> 
  41.                    <Text>Username</Text>  
  42.                    <TextInput 
  43.                          onChange={this._usernameChanged.bind(this)} 
  44.                          value={this.state.username} /> 
  45.                  </View
  46.             </View
  47.             <TouchableOpacity onPress={this._submit.bind(this)}>                 
  48.                 <View style={styles.btn}>                     
  49.                     <Text style={styles.btnText}> 
  50.                             Submit                         
  51.                     </Text> 
  52.                 </View>  
  53.             </TouchableOpacity> 
  54.         </View
  55.         ); 
  56.     } 

所有樣式都存儲在一個單獨的模塊中。

包裹在TouchableOpacity中的button組件應該單獨分離出來,這樣才能方便我們以后重復使用它。Image組件,以后也可能重復使用,所以也應該把它分離出來。

做了一些改變之后的樣子:

 

  1. import React, { Component, PropTypes } from 'react'
  2. import { 
  3.     Text, 
  4.     TextInput, 
  5.     View
  6.     TouchableOpacity 
  7. from 'react-native'
  8. import styles from './styles.ios'
  9.  
  10. class Avatar extends Component{ 
  11.     constructor(props){ 
  12.         super(props); 
  13.     } 
  14.     render(){         
  15.         if(this.props.imgSrc){             
  16.             return(                 
  17.                 <View style={styles.avatarBlock}> 
  18.                     <Image 
  19.                         source={this.props.imgSrc} 
  20.                         style={styles.avatar}/> 
  21.                 </View
  22.              ) 
  23.          } 
  24.          return null
  25.     } 
  26. Avatar.propTypes = { 
  27.     imgSrc: PropTypes.object 
  28.  
  29. class FormItem extends Component{ 
  30.     constructor(props){ 
  31.         super(props); 
  32.     } 
  33.     render(){ 
  34.         let title = this.props.title; 
  35.         return(  
  36.             <View style={styles.formItem}> 
  37.                 <Text> 
  38.                     {title}                
  39.                 </Text> 
  40.                <TextInput 
  41.                    onChange={this.props.onChange} 
  42.                    value={this.props.value} /> 
  43.             </View
  44.         ) 
  45.     } 
  46. FormItem.propTypes = { 
  47.     title: PropTypes.string, 
  48.     value: PropTypes.string, 
  49.     onChange: PropTypes.func.isRequired 
  50.  
  51. class Button extends Component{ 
  52.     constructor(props){ 
  53.         super(props); 
  54.     } 
  55.     render(){ 
  56.         let title = this.props.title; 
  57.         return(             
  58.             <TouchableOpacity onPress={this.props.onPress}> 
  59.                 <View style={styles.btn}> 
  60.                     <Text style={styles.btnText}> 
  61.                         {title}                     
  62.                     </Text> 
  63.                 </View
  64.             </TouchableOpacity> 
  65.         ) 
  66.     } 
  67.              
  68. Button.propTypes = { 
  69.     title: PropTypes.string, 
  70.     onPress: PropTypes.func.isRequired 
  71. export default class SomeContainer extends Component { 
  72.     constructor(props){ 
  73.         super(props); 
  74.         this.state = { 
  75.             username:null 
  76.         } 
  77.     } 
  78.     _usernameChanged(event){ 
  79.         this.setState({ 
  80.             username:event.nativeEvent.text  
  81.         }); 
  82.     } 
  83.     _submit(){ 
  84.         if(this.state.username){ 
  85.             console.log(`Hello, ${this.state.username}!`); 
  86.         } 
  87.         else
  88.             console.log('Please, enter username'); 
  89.         } 
  90.     } 
  91.     render() { 
  92.         return (                                  
  93.         <View style={styles.container}> 
  94.                 <Avatar imgSrc={this.props.image} /> 
  95.                 <View style={styles.form}> 
  96.                     <FormItem 
  97.                       title={"Username"
  98.                       value={this.state.username} 
  99.                       onChange={this._usernameChanged.bind(this)}/> 
  100.                 </View
  101.                 <Button 
  102.                     title={"Submit"
  103.                     onPress={this._submit.bind(this)}/> 
  104.             </View
  105.         ); 
  106.     } 

現在的代碼看起來更多了 – 因為我們為Avatar,FormItem和Button組件添加了包裝器,但現在我們可以在需要的地方重復使用這些組件。我們可以將這些組件移動到單獨的模塊中,并導入我們需要的任何地方。我們也可以添加其他一些Props,例如style,TextStyle,onLongPress,onBlur,onFocus。而且這些組件是完全可以定制的。

注意,一定不要深度定制一個小組件, 這樣會使組件過于繁瑣,代碼會變的很難閱讀。即使現在添加新屬性的想法看起來像是解決任務的最簡單的方法,將來這個小小的屬性在閱讀代碼時可能會引起困惑。

關于理想的smart/dumb組件,看一下這個:

 

  1. class Button extends Component{ 
  2.     constructor(props){ 
  3.         super(props); 
  4.     } 
  5.     _setTitle(){         
  6.         const { id } = this.props;         
  7.         switch(id){             
  8.             case 0:                 
  9.                 return 'Submit';             
  10.             case 1:                 
  11.                 return 'Draft';             
  12.             case 2:                 
  13.                 return 'Delete';             
  14.             default:                 
  15.                 return 'Submit'
  16.          } 
  17.     } 
  18.                  
  19.     render(){            
  20.         let title = this._setTitle();              
  21.         return(             
  22.             <TouchableOpacity onPress={this.props.onPress}> 
  23.                 <View style={styles.btn}> 
  24.                     <Text style={styles.btnText}> 
  25.                         {title}                     
  26.                     </Text> 
  27.                </View
  28.            </TouchableOpacity> 
  29.         ) 
  30.     } 
  31. Button.propTypes = { 
  32.     id: PropTypes.number, 
  33.     onPress: PropTypes.func.isRequired 
  34. export default class SomeContainer extends Component { 
  35.     constructor(props){ 
  36.         super(props); 
  37.         this.state = { 
  38.             username:null 
  39.         } 
  40.     } 
  41.     _submit(){ 
  42.         if(this.state.username){ 
  43.             console.log(`Hello, ${this.state.username}!`); 
  44.         } 
  45.         else
  46.             console.log('Please, enter username'); 
  47.         } 
  48.     } 
  49.     render() { 
  50.         return (             
  51.             <View style={styles.container}> 
  52.                 <Button 
  53.                     id={0} 
  54.                     onPress={this._submit.bind(this)}/> 
  55.             </View
  56.          
  57.     } 

我們已經“升級”了Button組件。用一個叫做“id”的新屬性來替換屬性“title”。現在Button組件就變的“靈活”了。傳0 – button組件會顯示“submit”。傳2 – 顯示“delete”。但這可能會有一些問題。

Button被創建為一個dumb組件 – 只是為了顯示數據,傳遞數據這件事由它的更高一級的組件來完成。

如果我們將5作為id傳遞給這個組件,我們就需要更新組件,以便讓它適應這個改動。dumb組件,就是細分的小組件,它只要接收props就好了,如果有state也應該與全局的無關。

7.行內樣式

在使用RN布局之后,我遇到了行內樣式的寫作風格問題。類似這樣:

 

  1. render() {     
  2.     return (         
  3.         <View style={{flex:1, flexDirection:'row', backgroundColor:'transparent'}}> 
  4.             <Button 
  5.                 title={"Submit"
  6.                 onPress={this._submit.bind(this)}/> 
  7.         </View
  8.     ); 

當你這樣寫的時候,你會想:“暫時這樣寫,等我在模擬器中運行之后 – 如果布局沒問題,再把樣式移動到單獨的模塊。”也許這是一個好的想法。但是..不幸的是,你往往會選擇性忽略行內樣式…

一定要在獨立的模塊中編寫樣式,遠離行內樣式。

8.使用redux驗證表單

要使用redux來驗證表單,我需要在reducer中創建action,actionType單獨的字段,這樣做很麻煩。

所以我決定只借助state來完成驗證。沒有reducers,types等等,只是在container級別上的純功能函數。從action和reducer文件中刪除不必要的函數,這個策略對我幫助很大。

9.過于依賴zIndex

很多人從web開發轉到RN開發。在web中有一個css屬性z-index,它可以幫助我們在需要的層級顯示我們想要的內容。

在RN中,一開始沒有這樣的特性。但后來又被添加進來了。起初,使用起來還挺簡單的。只需為元素設置zIndex屬性,它就會按照任何你想要的圖層順序來渲染。但是在Android上測試之后…現在我只用zIndex來設置展示層的結構。

10.不仔細閱讀外部組件的源碼

你可以引入外部組件來節省你的開發時間。

但有時這個模塊可能會中斷,或者不像描述的那樣工作。閱讀源碼你才會明白哪里出現了錯誤。也許這個模塊本身就有問題,或者你只是用錯了。另外 – 如果你仔細閱讀其他模塊的源碼,你將會學習到如何構建自己的組件。

11.要小心手勢操作和Animated API。

RN為我們提供了構建完全原生應用程序的能力。怎么讓用戶感覺是原生應用?頁面布局,滑動手勢,還是展示動畫?

當你使用View,Text,TextInput和其他RN提供的默認模塊時,手勢和動畫應該由PanResponder和Animated API來處理。

如果你是從web轉過來的rn開發工程師,獲取用戶的手勢操作可能會有些困難,你需要區分什么時候開始,什么時候結束,長按,短按。你可能還不夠清楚怎么在RN中模擬這些動畫操作。

這是我用PanResponder和Animated建立的Button組件。這個button是為了捕捉用戶手勢而構建的。例如 – 用戶按下項目,然后將手指拖到一邊。在按下按鈕時,借助于動畫API,構建button按壓下的不透明度的變化:

 

  1. 'use strict'
  2. import React, { Component, PropTypes } from 'react'
  3. import { Animated, View, PanResponder, Easing } from 'react-native'
  4. import moment from 'moment'
  5. export default class Button extends Component { 
  6.     constructor(props){ 
  7.         super(props);                 
  8.         this.state = { 
  9.             timestamp: 0 
  10.         };         
  11.         this.opacityAnimated = new Animated.Value(0);                 
  12.         this.panResponder = PanResponder.create({ 
  13.    onMoveShouldSetPanResponderCapture: (evt, gestureState) => true
  14.    onStartShouldSetResponder:() => true
  15.    onStartShouldSetPanResponder : () => true
  16.    onMoveShouldSetPanResponder:(evt, gestureState) => true
  17.    onPanResponderMove: (e, gesture) => {},  
  18.    onPanResponderGrant: (evt, gestureState) => {    
  19.         /**THIS EVENT IS CALLED WHEN WE PRESS THE BUTTON**/ 
  20.        this._setOpacity(1);        
  21.        this.setState({ 
  22.            timestamp: moment() 
  23.        });        
  24.        this.long_press_timeout = setTimeout(() => {             
  25.            this.props.onLongPress(); 
  26.        }, 1000); 
  27.    }, 
  28.    onPanResponderStart: (e, gestureState) => {}, 
  29.    onPanResponderEnd: (e, gestureState) => {}, 
  30.    onPanResponderTerminationRequest: (evt, gestureState) => true
  31.    onPanResponderRelease: (e, gesture) => {    
  32.        /**THIS EVENT IS CALLED WHEN WE RELEASE THE BUTTON**/ 
  33.        let diff = moment().diff(moment(this.state.timestamp));        
  34.        if(diff < 1000){            
  35.            this.props.onPress(); 
  36.        } 
  37.        clearTimeout(this.long_press_timeout);        
  38.        this._setOpacity(0);        
  39.        this.props.releaseBtn(gesture); 
  40.    } 
  41.      }); 
  42.     } 
  43.     _setOpacity(value){     
  44.      /**SETS OPACITY OF THE BUTTON**/ 
  45.         Animated.timing(         
  46.         this.opacityAnimated, 
  47.         { 
  48.             toValue: value, 
  49.             duration: 80, 
  50.         } 
  51.         ).start(); 
  52.     } 
  53.          
  54.     render(){         
  55.         let longPressHandler = this.props.onLongPress, 
  56.             pressHandler = this.props.onPress, 
  57.             image = this.props.image, 
  58.             opacity = this.opacityAnimated.interpolate({ 
  59.               inputRange: [0, 1], 
  60.               outputRange: [1, 0.5] 
  61.             });         
  62.          
  63.         return(             
  64.             <View style={styles.btn}> 
  65.                 <Animated.View 
  66.                    {...this.panResponder.panHandlers}                   style={[styles.mainBtn, this.props.style, {opacity:opacity}]}> 
  67.                     {image}                
  68.                 </Animated.View
  69.             </View
  70.         ) 
  71.     } 
  72. Button.propTypes = { 
  73.     onLongPress: PropTypes.func, 
  74.     onPressOut: PropTypes.func, 
  75.     onPress: PropTypes.func, 
  76.     style: PropTypes.object, 
  77.     image: PropTypes.object 
  78. }; 
  79. Button.defaultProps = { 
  80.     onPressOut: ()=>{ console.log('onPressOut is not defined'); }, 
  81.     onLongPress: ()=>{ console.log('onLongPress is not defined'); }, 
  82.     onPress: ()=>{ console.log('onPress is not defined'); }, 
  83.     style: {}, 
  84.     image: null 
  85. }; 
  86. const styles = { 
  87.     mainBtn:{ 
  88.         width:55, 
  89.         height:55, 
  90.         backgroundColor:'rgb(255,255,255)',   
  91.     } 
  92. }; 

首先,初始化PanResponder對象實例。它有一套不同的操作句柄。我感興趣的是onPanResponderGrand(當用戶觸摸按鈕時觸發)和onPanResponderRelease(當用戶從屏幕上移開手指時觸發)兩個句柄;

我還設置了一個動畫對象實例,幫助我們處理動畫。將其值設置為零;然后我們定義_setOpacity方法,調用時改變this.opacityAnimated的值。在渲染之前,我們插入this.opacityAnimated為正常的opacity值。我們不使用View而是使用Animated.View模塊為了使用動態變化的opacity值。

通過上面的例子,你會發現Animated API不難理解,你只需要閱讀相關的API文檔,以確保你的應用程序***運行。希望這個例子能幫你開個好頭。

在使用React Native開發時可能會遇到很多問題,希望這篇文章能幫助你避免一些錯誤。

責任編輯:未麗燕 來源: 前端工坊公眾號
相關推薦

2021-12-16 06:52:33

Ceph分布式對象

2017-10-17 16:23:58

函數式編程ReduxReact

2022-06-10 08:01:17

ReduxReact

2020-10-08 18:12:36

數據科學職位面試數據科學家

2016-08-12 13:55:06

2020-04-20 18:15:46

開發自信技術

2020-05-17 16:10:36

開發人員軟件開發開發

2017-09-11 14:35:34

編輯器開發環境React

2015-03-02 15:30:11

2015-04-17 09:47:57

2016-10-31 11:26:13

ReactRedux前端應用

2021-07-25 21:36:24

Windows操作系統功能

2016-11-23 16:48:20

react-nativandroidjavascript

2018-07-06 15:00:50

碼農科技開發

2022-04-02 15:11:04

工具APIUI

2020-12-22 13:49:23

開發編碼框架

2017-03-21 21:37:06

組件UI測試架構

2015-08-06 17:15:28

2021-03-09 09:52:55

技術React Hooks'數據

2015-03-20 09:34:40

點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: a级片播放 | 欧美一级片中文字幕 | 精品国产乱码久久久久久图片 | 久国久产久精永久网页 | 欧美成人一级 | 久久久久九九九九 | 日本一区二区在线视频 | 亚洲九九精品 | 久久一| 国产免费一区二区 | 羞羞视频在线免费 | 精品真实国产乱文在线 | 羞羞的视频在线看 | 国产精品黄色 | 亚洲精品福利视频 | 久久青 | 欧美日韩亚洲国产 | 国产偷录视频叫床高潮对白 | 日韩成人精品一区二区三区 | 久久精品一 | 成人黄色在线视频 | 午夜免费福利电影 | 久久av网| 亚洲综合中文字幕在线观看 | 日韩三级电影一区二区 | 97精品视频在线 | 极品粉嫩国产48尤物在线播放 | 凹凸日日摸日日碰夜夜 | av免费网站在线 | 黄免费观看视频 | av一二三区 | 国内精品久久久久久久影视简单 | 欧美三级网站 | 97超碰人人草 | 欧美午夜激情在线 | 国产a级毛片 | 国产成人精品一区二区在线 | 91精品国产777在线观看 | 国产成人综合亚洲欧美94在线 | 超碰av免费| 久久免费观看视频 |