如何使用 React-Native 获取父 ListView 组件中子复选框组件的状态?
How can I get the state of child checkbox components within a parent ListView component using 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>
);
}
}
提前致谢!
这是您应该做的。我在代码中加入了注释来解释。应该有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
对象的一部分。
我有一个带有复选框的选项列表和一个父 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>
);
}
}
提前致谢!
这是您应该做的。我在代码中加入了注释来解释。应该有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
对象的一部分。