快速學習RN之屬性props和狀態state(二)
繼上一篇學習了RN的環境搭建和demo的執行應該有了一定的瞭解,接下來我們就學習影響頁面變化的兩個重要元素 props 和 state
程式碼除錯
在介紹這倆兄弟前,先補充一下demo的執行及除錯方法 ,後面就斷點除錯及瀏覽器除錯再詳細介紹
在 react-native run-android
執行成功跑起來後,如果想修改頁面和修改程式碼邏輯後看效果,不需要像原生一樣,再run一次,安卓的專案如果moudle比較多的話building的時間真的是很長.
-
搖一搖會彈出一個選單,開啟Enable Live Reload
-
VSCode左下角設定,進入命令面板搜尋 React Native: Start Packager 找到後點擊啟動
-
待啟動成功後,可以嘗試修改程式碼然後手動儲存 ctrl+s 就會自動更新程式碼看到效果了
除錯說完了,下面開始介紹倆兄弟
props:
我個人理解,該屬性的值是在父元件中引用子元件時候指定的,該屬性是子元件中定義的,比如新建一個蘋果元件,蘋果有顏色的屬性,在構建這個元件的時候,指定一個color屬性,在父元件使用的時候再指定一個具體的顏色值,那麼最後子元件就會拿到這個值,顯示相應顏色的蘋果.
舉例說明:
新建一個蘋果元件 AppleComponent
import * as React from "react"; import { Text, View } from "react-native"; /** * 定義屬性介面 */ interface AppleComponentProps{ //蘋果元件顏色屬性 apple_color:string } /** * 自定義一個蘋果元件 */ export default class AppleComponent extends React.Component<AppleComponentProps>{ constructor(props:any){ super(props); } render(){ //什麼顏色,由父親(父元件)來定 當然也可以自己給自己定義一個預設的樣子,下面會說 return( <View> <Text>我是一個{this.props.apple_color}的蘋果元件</Text> </View> ) } } 複製程式碼
我們在蘋果元件裡定義了一個屬性apple_color 用於設定他的顏色
在render時候通過this.props.apple_color來獲取使用 它的具體值來自父元件的指定 看父元件就明白了
//匯入蘋果元件的路徑 根據你自己的路徑 import AppleComponent from './src/Apple' //該元件是啟動的首頁元件 export default class App extends Component<Props> { render() { return ( <AppleComponent apple_color="紅色"/> ); } } 複製程式碼
看到了吧, 這一句引用了子元件,並指定了該子元件的屬性值,值就是在這裡設定的,傳遞到子元件後就是固定了不能改變了.
這裡只是傳遞了一個屬性,實際情況會有很多,這樣一個個傳比較麻煩 下面貼出多屬性時候的寫法
interface AppleComponentProps{ //蘋果元件顏色屬性 apple_color:string //蘋果元件重量屬性 apple_weight:number //蘋果元件價格屬性 apple_price:number } /** * 自定義一個蘋果元件 */ export default class AppleComponent extends React.Component<AppleComponentProps>{ constructor(props:any){ super(props); } render(){ //什麼顏色,由父親(父元件)來定 當然也可以自己給自己定義一個預設的樣子 return( <View> <Text>我是一個{this.props.apple_color}的蘋果元件</Text> <Text>我的重量是:{this.props.apple_weight}kg</Text> <Text>我的價格是:{this.props.apple_price}元</Text> </View> ) } } 複製程式碼
export default class App extends Component<Props> { render() { return ( <AppleComponent apple_color="紅色" apple_weight={1.8} apple_price={9.9}/> ); } } 複製程式碼
在一個引數的基礎上依次增加了兩個屬性,使用方法和上面一致,可以看到,傳遞的屬性值在比較多的情況下寫法還是比較麻煩的,下面貼出比較簡單的寫法
export default class App extends Component<Props> { render() { var params = { apple_color :'紅色', apple_weight: 1.8, apple_price: 9.9} return ( <AppleComponent {...params}/> ); } } 複製程式碼
{...params} 的寫法意思代表了把全部的引數一起傳遞過去了, 這樣簡單多了吧.
當然如果有時候想只傳遞部分屬性 也是可以的.使用解構賦值
export default class App extends Component<Props> { render() { var params = { apple_color :'紅色', apple_weight: 1.8, apple_price: 9.9} var { apple_color,apple_weight} = params return ( <AppleComponent apple_color={apple_color},apple_weight={apple_weight}/> ); } } 複製程式碼
但是這樣寫 編譯器會提示有錯誤 少了一個屬性,因為這裡我使用了介面的方式定義了屬性 通過泛型傳遞給了
interface AppleComponentProps{ //蘋果元件顏色屬性 apple_color:string //蘋果元件重量屬性 apple_weight:number //蘋果元件價格屬性 apple_price:number } export default class AppleComponent extends React.Component<AppleComponentProps>{...} 複製程式碼
因此,有了介面的限定,只能按照介面的規範不能缺少屬性,全部要覆寫.
這時候如果比較倔強,就不想全部屬性賦值傳遞呢? 好的,經過探索,可以的,瞭解kotlin的應該知道,有一個可空的特性,使用?標識,對,一樣的,我們只需要在屬性上加一個可空標識,那麼這個屬性就可以不傳了.
apple_price?:number 複製程式碼
這樣就不會提示錯誤了
還有一種方式那就是不用介面的方式定義屬性,直接在泛型裡傳入any任意值 也是不會提示錯的,想怎麼傳自己隨便了.
React.Component<any> 複製程式碼
接下來你會發現,如果部分屬性值沒有指定,那麼ui上本來要顯示的內容,由於部分引數沒傳,就會顯示空了,那麼就有一個給屬性設定預設值的方法防止值為空 這裡只是為了學習 實際上並不一定會用的上
//給屬性設定預設的值 static defaultProps = { apple_color: "綠色", apple_weight:2.5, apple_price:19.9 }; //也可以這樣寫 推薦直接這樣寫 上面的是js的時候的寫法 //給屬性設定預設的值 private apple_color: string = "綠色"; private apple_weight: number = 2.5; private apple_price: number = 19.9; //注意,在建構函式中進行賦值 this.apple_color = this.props.apple_color; this.apple_weight = this.props.apple_weight; //由於該屬性設定了可空 ts檢測不能直接賦值,採用如下寫法即可 this.apple_price = this.props.apple_price? this.props.apple_price:this.apple_price 複製程式碼
在元件的最開始地方加上預設值 若父元件沒有賦值,那麼就顯示預設的值 這裡只有價格沒傳,使用的是預設的價格
以上就是我對props的理解,對於屬性型別還有一個約束限定型別的內容,這塊感覺暫時簡單說下,後面遇到有用的地方再詳細說明,其實就是對屬性的型別就行型別的指定,如果在指定屬性值時候型別不匹配,編譯器便會提示錯誤.
首先新增依賴庫
yarn add prop-types 複製程式碼
元件中匯入
import PropTypes from "prop-types"; 複製程式碼
元件中使用 舉例
static propTypes = { name: PropTypes.string.isRequired, //isRequired就是不可空 必傳屬性 age: PropTypes.number, //指定數字型別 sex: PropTypes.string //指定字串型別 }; 複製程式碼
關於props還有很多需要深入理解的,先暫時研究到這,我們需要快速掌握使用.
state:
我理解是在元件本身內部屬性變數,props是外部指定賦值,一旦賦值,在元件內接收後便不會再改邊,這樣對於UI的重新整理,動態變化是做不到支援的,所以就有了state這個物件來控制頁面狀態的重新整理變化
舉例說明
還拿上面的蘋果元件來說,顏色,價格,重量都是指定該元件的屬性,在初始化前就定義好了樣式的,如果想在這之後改變蘋果元件的狀態,比如點選蘋果元件 改變顏色或者改變他的顯示內容等等
實際上應該用在載入網路資料多一些吧
這裡實現每過1s 改變蘋果元件的樣式(顏色和數量變化),先看下效果

首先通過介面定義我們需要的狀態 參考程式碼:
interface AppleComponentState { //是否改變顏色 ischange: boolean; //蘋果數量 apple_num: number; } //傳入Component<P,S> 對應的S的泛型中 前面P對應的props屬性介面物件 export default class AppleComponent extends React.Component<AppleComponentProps,AppleComponentState> {....} 複製程式碼
在建構函式中進行狀態變數的賦值
//建構函式 constructor(props: AppleComponentProps) { super(props); //屬性賦值 this.apple_color = this.props.apple_color; this.apple_weight = this.props.apple_weight; this.apple_price = this.props.apple_price? this.props.apple_price:this.apple_price //狀態賦值 this.state = { ischange: false, apple_num : 1 }; //執行狀態變化的函式 setInterval(() => { this.setState(previousState => { return { ischange: !previousState.ischange, apple_num: previousState.apple_num + 1 }; }); }, 1000); } 複製程式碼
上面程式碼中setInterval()函式即進行了蘋果元件狀態變化的操作,動態改變蘋果元件ischange,apple_num的值,來重新整理介面顯示的內容 最終呼叫的是this.setState()函式進行狀態的改變, previousState 為上一次狀態物件,我理解就是每次setState都會儲存一個state物件存入一個物件的佇列中,類似棧,這塊理解不深,暫且不說了,通過previousState 引用可以拿到的是上一次的狀態物件即可.
下面是渲染的參考程式碼 也就是狀態變數的呼叫 this.state.xxxxx 獲取的是狀態更新後的最新的值
render() { //什麼顏色,由父元件來定 當然也可以自己給自己定義一個預設的樣子 let colorvalue = this.state.ischange ? "#ff0033" : "#000000"; return ( <View style={styles.container}> <Text style={{ color: colorvalue }}> 我是一個 {this.apple_color} 的蘋果元件 </Text> <Text style={{ color: colorvalue }}> 我的重量是: {this.apple_weight} kg </Text> <Text style={{ color: colorvalue }}> 我的價格是: {this.apple_price}元 </Text> <Text style={{ fontSize: 20, margin: 10, color: colorvalue }}> {this.state.apple_num} </Text> </View> ); } 複製程式碼
以上是通過一個舉例來理解state的一個使用,實際應用開發中一般很少用到了,下面就拿一個實際應用開發的簡單的業務來實踐一下state的使用 通過網路請求一個文章列表資料 進行展示 先看效果

首先,新建一個元件,React是一個元件化思想的框架,所以寫一個頁面基本都是新建一個Component,這裡命名為 HomeArtical.tsx
第一步: 定義屬性和狀態 先別急 分析一下 雖然功能簡單,通過網路請求 獲取資料 列表展示
這裡面可能需要用到的屬性有哪些呢?
屬性:那些用於函式業務邏輯控制的一些變數
- url:string //介面請求地址
- curPageIndex;number //當前頁碼索引
- pageSizes:number //每頁資料大小
- .....
做分頁載入 下拉重新整理 上拉載入更多 等等會用很多 根據需要自行增加
狀態:那些用於介面重新整理相關的變數
- data:[] //資料來源肯定要有 也是唯一必須的
- ....
下面是為實現列表資料單純的展示 定義的屬性和狀態 參考程式碼:
//屬性 interface HomeArticalProps { //介面地址 artical_url?: string; //當前頁碼索引 page_index?: number; } //狀態 interface HomeArticalStates { //文章資料來源 data: string[]; } //傳入泛型中 export default class HomeArtical extends React.Component< HomeArticalProps, HomeArticalStates > {......} 複製程式碼
這裡在說明一下 為啥用介面來定義屬性狀態呢,我想是為了外部父元件傳入屬性的時候使用this.props.xxxx即可獲取到傳入的屬性值.在vscode編輯器也會有屬性提示和錯誤檢查,由於剛學習,也是參考了同事的程式碼來寫的,寫到這,我要去看typescript文件了,不能誤人子弟啊 不會TypeScript的去多看看文件 TypeScript.宣告合併 的介面合併TypeScript 文件
下面繼續,定義好了屬性和狀態後開始賦值
預設賦值了一些初始值
//頁碼 private page_index: number = 0; //請求介面 private artical_url: string = "http://www.wanandroid.com/article/list/"; //請求url, 預設載入首頁文章列表第一頁 private artical_api: string = this.artical_url + this.page_index + "/json"; 複製程式碼
建構函式給屬性和狀態賦值 值來自父元件或本身預設值
constructor(props: HomeArticalProps) { super(props); //子元件內部屬性引用重新賦值 值來自父元件 this.artical_url = this.props.artical_url ? this.props.artical_url : this.artical_url; this.page_index = this.props.page_index ? this.props.page_index : this.page_index; this.artical_api = this.artical_url + this.page_index + "/json"; this.state = { //資料來源 data: [] }; 複製程式碼
編寫介面 這裡只需要用到一個列表元件 使用原生的 FlatList 即可 參考程式碼:
//渲染頁面 public render() { return ( <FlatList //列表元件 style={styles.container} //樣式 data={this.state.data} //繫結資料來源 keyExtractor={this._keyExtractor} //每條資料設定不一樣的key ListHeaderComponent={this.renderHeader} //列表頭部檢視 ItemSeparatorComponent={this.renderSeparator} //分割線 renderItem={this.renderItem} //item條目 /> ); } 複製程式碼
編寫網路請求 使用原生的fetch
//獲取資料 private getArticalDatas(curPage: number) { fetch(this.artical_api) .then(response => response.json()) .then(responseData => { this.setState({ //修改資料來源 重新整理介面 data: this.state.data.concat(responseData.data.datas) }); }) .catch(error => { this.setState({}); }); } 複製程式碼
開始請求資料
元件的生命週期的介面渲染完成後開始載入資料
//開始請求資料 componentDidMount() { this.getArticalDatas(0); } 複製程式碼
至此這個頁面就完成了,當然加上loading 和 上拉載入更多 下拉重新整理會更完整點 之前寫過js版本 不過要換成ts的寫法 我還沒有改,後面慢慢加入.這次先學會屬性和狀態的使用和個人的理解.
寫了這麼多 其實都是最基礎的用法了,深入理解的東西還要再實際專案中慢慢悟.本篇是快速學習,直接上手專案開發的筆記,用於加深記憶,如果有一起學習的可以和我一起.持續更新.
計劃後面學習
- 頁面跳轉及引數傳遞第三方庫的使用
- tsx中引用js的宣告
- mobx狀態管理
- 程式碼除錯
- 打包釋出
- 熱更新
- 效能優化及深入理解
- ......
查閱完整demo中的程式碼 可以去我的github 地址是: ofollow,noindex">RNDemo