2016-05-16 46 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

缺失的链接是我没有更新数据源,我现在就试试,谢谢 –

相关问题