我有一个搜索屏幕,包含Input And TopTabs"Songs,Artists",
当我在搜索后从API获得数据时,我做了两件事
1-我设置State以显示TopTab组件"true/false"2-发送一个保存歌曲的动作&redux存储中的艺术家数据。
这很好。
但在topTab组件中,正如我之前所说,我有两个选项卡"歌曲,艺术家">
例如,在Songs组件中,我想操作数据以实现我的情况,因此在componentDidMount
中,我从redux映射Songs数组,并将新数据推送到组件状态。
但它工作不好!
第一次,我从redux获得的歌曲是空的[],尽管当我从API 获得数据时,它成功地保存在了redux存储中
那么,我如何处理这种情况以避免数据发生变异呢?
Search.js"主屏幕">
onSearch = async () => {
const {searchText} = this.state;
if (searchText.length > 0) {
this.setState({onBoarding: false}); // to appear the TopTab Component
try {
let response = await API.post('/search', {
name: searchText,
});
let {
data: {data},
} = response;
let artists = data.artists.data;
let songs = data.traks.data;
this.props.getResult(songs, artists);
}
catch (err) {
console.log(err);
}
}
render(){
<View style={styles.searchHeader}>
<Input
onChangeText={text => this.search(text)}
value={this.state.searchText}
onSubmitEditing={this.onSearch}
returnKeyType="search"
/>
</View>
{this.state.onBoarding ? (
<SearchBoard />
) : (
<SearchTabNavigator /> // TopTabs component
)}
}
歌曲标签
...
componentDidMount() {
console.log('props.songs', this.props.songs); // Empty []
let All_tunes = [];
if (this.props.songs?.length > 0) {
console.log('mapping...');
this.props.songs.map(track =>
All_tunes.push({
id: track.id,
name: track.name,
url: URL + track.sounds,
img: URL + track.avatar,
}),
);
this.setState({All_tunes});
}
}
...
const mapStateToProps = state => {
return {
songs: state.searchResult.songs,
};
};
编辑
我使用componentDidUpdate()
生命周期解决了这个问题
如果你有其他方法,请告诉我!
歌曲标签
manipulateSongs = arr => {
let All_tunes = [];
arr.map(track =>
All_tunes.push({
id: track.id,
name: track.name,
url: URL + track.sounds,
img: URL + track.avatar,
}),
);
this.setState({All_tunes});
};
componentDidMount() {
if (this.props.songs?.length > 0) {
this.manipulateSongs(this.props.songs);
console.log('mapping...');
}
}
componentDidUpdate(prevProps) {
if (prevProps.songs !== this.props.songs) {
this.manipulateSongs(this.props.songs);
}
}
您所指的问题与JavaScript中异步代码的处理方式有关(反过来又与react redux有关(。当组件最初装载时,redux存储会将其初始状态传递给SongsTab.js
组件。这似乎是一个空数组。
任何API调用都是异步操作,在promise被解析/拒绝并且数据被成功提取之前,都不会更新redux存储。任何HTTP请求都要比向DOM绘制元素花费更长的时间才能完成。因此,您的组件在几毫秒后用API调用的响应更新之前加载默认数据。
使用基于类的组件处理它的方式很好。您可能可以添加一些优化,但它应该按预期工作。您甚至可以选择在从API获取数据时渲染Spinner组件。
如果您想要使用更现代的React模式的不同方法,可以尝试使用带有React钩子的等效版本。
const Songs = ({ fetchSongs, songs, ...props }) => {
React.useEffect(() => {
// dispatch any redux actions upon mounting
// handle any component did update logic here as well
}, [songs])
// ...the rest of your component
}
以下是useEffect钩子的文档。