React 通过组件传递数据
React transfer data through components
我有 parent 组件和 child(listView) 组件。我的目标是将后端调度数据从 parent 发送到 child。我通过单击按钮实现了这一点。问题是 child 在第二次 parent 按钮点击后呈现。也许我的错误在 componentWillReceiveProps
?
的某处
Parent:
class Parent extends Component {
constructor(props) {
super(props);
this.state = {
dataSource: '',
noRepos: false
};
}
componentWillReceiveProps(newProps) {
this.setState({
dataSource: newProps.data
});
this.validateData(newProps)
}
submitUsername() {
if(this.validateInput()){
this.props.dispatch({type: 'DUMMY', state: this.state.username});
} else {
this.setState({emptyInput: true});
}
}
render() {
return (
...
<View>
<ListViewComponent dataRecieved={this.state.dataSource} />
</View>
...
);
}
}
export default connect(state => {
return {
data: state.data,
};
})(Parent);
Child:
export default class ListViewComponent extends Component {
constructor(props) {
super(props);
this.state = {
dataSource: new ListView.DataSource({
rowHasChanged: (r1, r2) => r1 !== r2,
}),
};
}
propTypes: {
dataRecieved: PropTypes.func.string
};
componentWillReceiveProps(newProps) {
this.setState({
dataSource: this.state.dataSource.cloneWithRows(this.props.dataRecieved),
});
}
renderRow(rowData) {
return (
<View>
<Text>{rowData.name}</Text>
</View>
);
}
render() {
return (
<View>
<ListView dataSource={this.state.dataSource}
enableEmptySections={true}
renderRow={this.renderRow} />
</View>
);
}
}
好的,一般建议是始终保持单一的真实来源:
不要将 props 中已有的数据复制到内部组件状态。使用道具中的数据。
尝试创建尽可能无状态的组件(参见上文...使用 props,或者让组件监听 'store'。参见 Redux 或 AltJs)。
专门尝试解决您的问题:
在父级中替换:
<ListViewComponent dataRecieved={this.state.dataSource} />
和
<ListViewComponent dataRecieved={this.props.data} />
而在 ListViewComponent 中,不要这样做:
this.setState({
dataSource: this.state.dataSource.cloneWithRows(this.props.dataRecieved),
});
但是:
render() {
var ds = new ListView.DataSource({
rowHasChanged: (r1, r2) => r1 !== r2,
})
, dataSource = ds.cloneWithRows(this.props.dataRecieved);
return (
<View>
<ListView dataSource={dataSource}
enableEmptySections={true}
renderRow={this.renderRow} />
</View>
);
}
以上是未经测试的代码,但应作为遵循何种方法的指南。
您最初实现 ListViewComponent
的方式很好,您应该在刷新 ListView
时使用 componentWillReceiveProps
。那里的每个最佳实践都说要这样做(只是 Google react native redux listview
)。我在上面的评论中提到的你的实现中有一个小错误。此外,您 不应该 在 render
函数中重新创建 ListView.DataSource
,这对性能不利并且会破坏 rowHasChanged
在 ListView.DataSource
.
我说的错误在这里:
componentWillReceiveProps(newProps) {
this.setState({
dataSource: this.state.dataSource.cloneWithRows(this.props.dataRecieved),
});
}
应该是:
// ListViewComponent
componentWillReceiveProps(newProps) {
this.setState({
dataSource: this.state.dataSource.cloneWithRows(newProps.dataRecieved),
});
}
此外,您的 Parent
不应在其 state
中包含 dataSource
,只需将 data
直接传递给 ListViewComponent
,因为 Redux 正在传递它已经是 prop
:
class Parent extends Component {
constructor(props) {
super(props);
this.state = {
// ...
};
}
componentWillReceiveProps(newProps) {
// ...
}
submitUsername() {
if (this.validateInput()) {
this.props.dispatch({ type: 'DUMMY', ... });
} else {
// ...
}
}
render() {
return (
...
<View>
{/* this.props.data automatically comes from the `connect` wrapper below */}
<ListViewComponent dataRecieved={this.props.data} />
</View>
...
);
}
}
export default connect(state => {
return {
data: state.data,
};
})(Parent);
你也应该看看这个 gist。这是一个如何将 Redux 与 ListView
一起使用的示例。他的示例使用 cloneWithRowsAndSections
,但因为您没有节,所以您只需改用 cloneWithRows
即可。这个要点是由一位非常活跃的核心 React Native 开发人员编写的。
我有 parent 组件和 child(listView) 组件。我的目标是将后端调度数据从 parent 发送到 child。我通过单击按钮实现了这一点。问题是 child 在第二次 parent 按钮点击后呈现。也许我的错误在 componentWillReceiveProps
?
Parent:
class Parent extends Component {
constructor(props) {
super(props);
this.state = {
dataSource: '',
noRepos: false
};
}
componentWillReceiveProps(newProps) {
this.setState({
dataSource: newProps.data
});
this.validateData(newProps)
}
submitUsername() {
if(this.validateInput()){
this.props.dispatch({type: 'DUMMY', state: this.state.username});
} else {
this.setState({emptyInput: true});
}
}
render() {
return (
...
<View>
<ListViewComponent dataRecieved={this.state.dataSource} />
</View>
...
);
}
}
export default connect(state => {
return {
data: state.data,
};
})(Parent);
Child:
export default class ListViewComponent extends Component {
constructor(props) {
super(props);
this.state = {
dataSource: new ListView.DataSource({
rowHasChanged: (r1, r2) => r1 !== r2,
}),
};
}
propTypes: {
dataRecieved: PropTypes.func.string
};
componentWillReceiveProps(newProps) {
this.setState({
dataSource: this.state.dataSource.cloneWithRows(this.props.dataRecieved),
});
}
renderRow(rowData) {
return (
<View>
<Text>{rowData.name}</Text>
</View>
);
}
render() {
return (
<View>
<ListView dataSource={this.state.dataSource}
enableEmptySections={true}
renderRow={this.renderRow} />
</View>
);
}
}
好的,一般建议是始终保持单一的真实来源:
不要将 props 中已有的数据复制到内部组件状态。使用道具中的数据。
尝试创建尽可能无状态的组件(参见上文...使用 props,或者让组件监听 'store'。参见 Redux 或 AltJs)。
专门尝试解决您的问题:
在父级中替换:
<ListViewComponent dataRecieved={this.state.dataSource} />
和
<ListViewComponent dataRecieved={this.props.data} />
而在 ListViewComponent 中,不要这样做:
this.setState({
dataSource: this.state.dataSource.cloneWithRows(this.props.dataRecieved),
});
但是:
render() {
var ds = new ListView.DataSource({
rowHasChanged: (r1, r2) => r1 !== r2,
})
, dataSource = ds.cloneWithRows(this.props.dataRecieved);
return (
<View>
<ListView dataSource={dataSource}
enableEmptySections={true}
renderRow={this.renderRow} />
</View>
);
}
以上是未经测试的代码,但应作为遵循何种方法的指南。
您最初实现 ListViewComponent
的方式很好,您应该在刷新 ListView
时使用 componentWillReceiveProps
。那里的每个最佳实践都说要这样做(只是 Google react native redux listview
)。我在上面的评论中提到的你的实现中有一个小错误。此外,您 不应该 在 render
函数中重新创建 ListView.DataSource
,这对性能不利并且会破坏 rowHasChanged
在 ListView.DataSource
.
我说的错误在这里:
componentWillReceiveProps(newProps) {
this.setState({
dataSource: this.state.dataSource.cloneWithRows(this.props.dataRecieved),
});
}
应该是:
// ListViewComponent
componentWillReceiveProps(newProps) {
this.setState({
dataSource: this.state.dataSource.cloneWithRows(newProps.dataRecieved),
});
}
此外,您的 Parent
不应在其 state
中包含 dataSource
,只需将 data
直接传递给 ListViewComponent
,因为 Redux 正在传递它已经是 prop
:
class Parent extends Component {
constructor(props) {
super(props);
this.state = {
// ...
};
}
componentWillReceiveProps(newProps) {
// ...
}
submitUsername() {
if (this.validateInput()) {
this.props.dispatch({ type: 'DUMMY', ... });
} else {
// ...
}
}
render() {
return (
...
<View>
{/* this.props.data automatically comes from the `connect` wrapper below */}
<ListViewComponent dataRecieved={this.props.data} />
</View>
...
);
}
}
export default connect(state => {
return {
data: state.data,
};
})(Parent);
你也应该看看这个 gist。这是一个如何将 Redux 与 ListView
一起使用的示例。他的示例使用 cloneWithRowsAndSections
,但因为您没有节,所以您只需改用 cloneWithRows
即可。这个要点是由一位非常活跃的核心 React Native 开发人员编写的。