[React Native]基礎-父子組件之間的傳值和函數調用

組件的複用是 React 中非常重要的一個設計,使得界面佈局的重用十分便捷,我們可以根據自己的需要來自定義各種組件,這對於結構相似的 UI 構建是很友好的。

所以經常我們會出現如下的代碼結構(其中的 MyComponent 是自定義組件):

export default class Home extends Component{

  ...
  render(){
    <View>
      <MyComponent/>	
    </View>
  }
}

在這種結構中,Home 組件包含了 MyComponent 組件,形成父子組件關係,其中自然是少不了有數據的傳遞,甚至會需要調用互相的函數,那麼父子組件之間是如何傳值和函數調用的呢?

子組件獲取父組件的變量和函數

如果我們需要在 MyComponent 中獲取到 Home 頁面中的數據的話,可以使用通過 props 來傳遞。需要注意的是傳遞的數據,可以是普通的變量,也可以是函數。如例:

export default class Home extends Component {

  constructor(props) {
    super(props);
    this.state = {
      buttonText: '點擊調用父組件 Home 的函數',
    }
  }

  onMyButtonPress = () => {     //父組件的方法
    ShowToast('Home 中的方法');
  }

  render() {
    return (
      <View>
        <MyButton
          //傳遞 text 變量
          text={this.state.buttonText}  
          //傳遞 onMyButtonPress 作爲 子組件的 onPress 函數
          onPress={this.onMyButtonPress}  
        />
      </View>
    );
  }

}

class MyButton extends Component {
  render() {
    //獲取傳遞的 onPress 函數和 text 變量
    const {text, onPress} = this.props;
    return (
      <TouchableOpacity
        style={styles.button}
        //實際調用的是父組件傳過來的 onPress 函數
        onPress={onPress}		
      >
        <Text>{text}</Text>
      </TouchableOpacity>
    );
  }
}

(代碼重點表現 props 傳遞,省略了導入和樣式部分)

效果:

上部分的 MyButton, 按鈕中的文字和點擊事件都是外部父組件傳入的,本身不持有任何靜態變量。在此基礎上,我們可以加上自定義的樣式或者其他元素,就成爲一個可以複用的按鈕組件。

父組件獲取子組件的變量和函數

如果我們要在外部的父組件中獲取到子組件的值的話,那就需要使用到 ref 了。如果對 ref 不太熟,可以參見 [Refs and the DOM]

這裏,你可以簡單理解爲綁定 ref 就可以獲取到當前的 DOM 元素節點,從而獲取它的變量和函數。

怎麼操作呢?如下:

export default class Home extends Component {

  constructor(props) {
    super(props);
    this.state = {
      buttonText: '點擊調用父組件 Home 的函數',
    }
    //創建 MytextInput 的 ref
    this.myButton = React.createRef();
  }

  //輸出子組件中的變量,調用子組件方法
  onMyButtonPress = () => {
    //在調試控制檯輸出 輸入框中輸入的值
    console.log('輸入的值:' + this.mytextInput.current.state.inputText); 
    //調用 MyTextInput 內部的方法 innerMethod
    this.mytextInput.current.innerMethod();
    //將 MyTextInput 輸入框的內容清除掉 (clear是TextInput組件本身的方法)
    this.mytextInput.current.textInputRef.current.clear(); 
  }

  render() {
    return (
      <View>
        <MyTextInput
          ref={this.mytextInput}
        />
        <TouchableOpacity
          onPress={this.onMyButtonPress}
        >
          <Text>確認</Text>
        </TouchableOpacity>
      </View>
    );
  }

}


//自定義組件 MyTextInput
class MyTextInput extends Component {

  constructor(props) {
    super(props);
    this.state = {
      inputText: ''
    }
    this.textInputRef = React.createRef();
  }

  // MyTextInput 的普通方法
  innerMethod = () => {
    ShowToast('MyTextInput 內部方法');
  }

  render() {
    return (
      <View>
        <TextInput
          placeholder={'輸入內容後點擊按鈕'}
          style={styles.input}
          onChangeText={text => this.setState({inputText: text})}
          ref={this.textInputRef}
        />
      </View>
    );
  }
}

效果:

可見,子組件中的 TextInput 的輸入內容,可以在父組件中獲取並打印輸出出來, innerMethod 是定義在子組件中的函數,也可以在父組件中得以調用。而子組件的 TextInput 組件的 clear 方法(清除輸入框的內容),依然能被父組件正確調用。

至此,我們已經在父組件中獲取到子組件的變量和函數了。

回調函數

如果只是需要傳遞數值到父組件,不需要在父組件中調用子組件的方法,並且觸發的動作事件是在子組件中發生的話(比如子組件點擊之後需要將一個變量暴露到父組件中,在父組件的多個地方用於顯示),那可以考慮使用回調函數。

例如:在子組件中有一個輸入框,輸入完成後,點擊軟鍵盤的完成提交,暴露給父組件。

子組件中:

  //調用父組件的函數,傳入值
  onSubmitPress = () => {
    const {submitText} = this.props;
    //調用父組件傳過來的函數,傳入 值(輸入的文本)
    submitText(this.state.inputText);  
  }

  render() {
    return (
      <View>
        <TextInput
          onSubmitEditing={this.onSubmitPress}
          ...         
        />
      </View>
    );
  }

父組件中使用:

<MyTextInput
  //接收傳過來的值, setState
  submitText={text => this.setState({resultText: text})}  
  ref={this.myButton}
/>

這樣,我們在輸入完成後,提交方法,調用父組件傳過來的 submitText 函數,並傳入的輸入的文本,父組件的方法接收到再 setState 就獲得了這個變量。至此,父組件就獲取到了子組件中的變量。

在父組件傳值到子組件的過程中,如果層級較深,應該考慮使用狀態管理工具。子組件傳值到父組件,除了以上方法,還可以通過 useRef,useImperativeHandle 等 Hook API 達到訪問子組件數據的目的。這將在後面的 Hook 相關章節介紹,敬請期待。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章