2016-05-16 60 views
9

我有一個選項列表,其中包含複選框和父按鈕ListView中的完成按鈕。當完成按鈕被按下時,我想知道哪個複選框被選中。如何使用React-Native獲得父級ListView組件中子複選框組件的狀態?

我應該補充一點,我嘗試使用ChildCheckBox的回調函數來維護ListView中的選中框的數組。它工作正常,除非導航回到ListView,陣列將被重置,而複選框仍然出現在檢查。我寧願讓onDonePress()函數只是查詢哪些框被檢查,然後在那個時候作出相應的響應,而不是依賴維護一個數組的ListView

這裏是ListView

class ParentListView extends Component { 
    constructor(props) { 
    super(props); 
    this.state = { 
     dataSource: new ListView.DataSource({ 
     rowHasChanged: (row1, row2) => row1 !== row2, 
     }), 
    }; 
    } 

    componentDidMount() { 
    this.setState({ 
     dataSource: this.state.dataSource.cloneWithRows(ROW_DATA), 
    }); 
    } 

    onCheckPress() { 
    console.log('Check Pressed') 
    // callback from ChildCheckBoxCell...? 
    } 

    onDonePress() { 
    console.log('Done pressed') 
    // callback from ChildDoneCell...? 
    } 

    render() { 
    return (
     <ListView 
     dataSource={this.state.dataSource} 
     renderRow={this.renderRow.bind(this)} 
     style={styles.listView} 
     /> 
    ); 
    } 

    renderRow(cell) { 
    if (cell.type === 'ChildCheckBoxCell') { 
     return (
     <ChildCheckBoxCell onChange={() => this.onCheckPress()} /> 
    ); 
    } 

    if (cell.type === 'ChildDoneCell') { 
     return (
     <ChildDoneCell onDonePress={() => this.onDonePress()}/> 
    ); 
    } 
    } 
} 

這裏是ChildCheckBoxCell組件:

class ChildCheckBoxCell extends Component { 

constructor(props) { 
    super(props); 
    this.state = { 
     isChecked: false, 
    }; 
    } 

    onChange() { 
    this.setState({isChecked: !this.state.isChecked}); 
    //Callback... 
    this.props.onChange(); 
    } 

    render() { 
    return (
     <TouchableHighlight onPress={() => this.onChange()}> 
     <Text>{this.state.isChecked? 'Checked' : 'UnChecked'}</Text> 
     </TouchableHighlight> 
    ); 
    } 
} 

最後,這裏是ChildDoneCell組件

class ChildDoneCell extends Component { 

    onDonePress() { 
    //Callback... 
    this.props.onDonePress(); 
    } 

    render() { 
    return (
     <TouchableHighlight onPress={() => this.onDonePress()}> 
     <Text>DONE</Text> 
     </TouchableHighlight> 
    ); 
    } 
} 

提前感謝!

回答

4

這是你應該做的。我在代碼中加入了一些註釋來解釋。應該有6個步驟。

class ParentListView extends Component { 
    constructor(props) { 
    super(props); 
    this.state = { 
     dataSource: new ListView.DataSource({ 
     rowHasChanged: (row1, row2) => row1 !== row2, 
     }), 
    }; 
    } 

    componentDidMount() { 
    this.setState({ 
     dataSource: this.state.dataSource.cloneWithRows(ROW_DATA), 
    }); 
    } 

    // 1. Change your callback functions to class properties 
    // this way it is auto-bound to this class instance and you don't bind it during render, which 
    // creates rendering overhead. Notice how the selected `cell` is 
    // passed in here. It will be explained in the last steps how that happens. 
    onCheckPress = (cell) => { 
    // Update the `isChecked` state of this cell and update 
    // your `ListView.DataSource` with it 
    console.log('Check Pressed', cell); 
    // callback from ChildCheckBoxCell...? 
    }; 

    // 2. Do the same thing here as step 1. 
    onDonePress = (cell) => { 
    console.log('Done pressed', cell); 
    // callback from ChildDoneCell...? 
    } 

    render() { 
    return (
     <ListView 
     dataSource={this.state.dataSource} 
     renderRow={this.renderRow.bind(this)} 
     style={styles.listView} 
     /> 
    ); 
    } 

    renderRow(cell) { 
    if (cell.type === 'ChildCheckBoxCell') { 
     return (
     // 3. You should pass in the cell data down here AND you should 
     // pass a reference to your callback 
     <ChildCheckBoxCell cell={cell} onChange={this.onCheckPress} /> 
    ); 
    } 

    if (cell.type === 'ChildDoneCell') { 
     // 4. Do the same thing here, except change the reference of 
     // the callback to the other callback, obviously 
     return (
     <ChildDoneCell cell={cell} onDonePress={this.onDonePress}/> 
    ); 
    } 
    } 
} 

class ChildCheckBoxCell extends Component { 

    render() { 
    return (
     // 5. Dereference the function `onChange` and bind it to your 
     // `cell` object, don't worry about `null` changing your 
     // `this` context, it won't. This is how the `cell` object is 
     // passed an argument in the method on step 1. 
     <TouchableHighlight onPress={this.props.onChange.bind(null, this.props.cell)}> 
     {/* Stop using `state` to keep track of `isChecked`, you'll 
      lose this state if this ever is torn down and re-rendered 
      from the parent component */} 
     <Text>{this.props.cell.isChecked? 'Checked' : 'UnChecked'}</Text> 
     </TouchableHighlight> 
    ); 
    } 
} 

class ChildDoneCell extends Component { 

    render() { 
    return (
     // 6. This is the same thing as step 5. 
     <TouchableHighlight onPress={this.props.onDonePress.bind(null, this.props.cell)}> 
     <Text>DONE</Text> 
     </TouchableHighlight> 
    ); 
    } 
} 

你會發現,你可以在renderRow功能綁定cell數據,但不理想。遵循的經驗法則是,出於性能方面的原因,您想盡可能地將您的回調函數取消引用到您的子數據中,並且由於維護原因而更明確。這是該快捷方式的選擇:

// ParentListView 
renderRow(cell) { 
    if (cell.type === 'ChildCheckBoxCell') { 
    return (
     // No more passing of cell, but now I'm binding it with the 
     // cell object 
     <ChildCheckBoxCell onChange={this.props.onCheckPress.bind(null, cell)} /> 
    ); 
    } 

    if (cell.type === 'ChildDoneCell') { 
    // Same thing 
    return (
     <ChildDoneCell onDonePress={this.onDonePress.bind(null, cell)}/> 
    ); 
    } 
} 

// ChildCheckBoxCell 

render() { 
    return (
    // Notice how you lose the explicitness of your callback 
    // function and have no idea that this function implicitly passes 
    // the `cell` object because you prematurely bound it with the `cell` object 
    <TouchableHighlight onPress={this.props.onChange}> 
     <Text>{this.props.isChecked? 'Checked' : 'UnChecked'}</Text> 
    </TouchableHighlight> 
); 
} 

編輯

我更新的代碼,使更多的意義,並擺脫不必要的實例方法。我強烈建議您在ChildCheckBoxCell中刪除state,並在第一個示例中嘗試通過props將其作爲cell對象的一部分進行填充。

+0

感謝您的非常詳細的答案!我剛剛嘗試過實現它,出於某種原因,CheckboxCell不響應listView中所做的更改。在第1步中,我有'cell.isChecked =!cell.isChecked',但組件並不響應這些更改。另外,'ComponentWillReceiveProps()'不會在'CheckBoxCell'中被調用。 –

+0

更新數據源時,必須使用cloneWithRows。你是否熟悉它? – rclai

+0

缺失的鏈接是我沒有更新數據源,我現在就試試,謝謝 –

相關問題