reactjs - React Native 钩子,useRef 和 useEffect
问题描述
我正在尝试使用 React Native将类组件转换为功能性组件。
我的Search
组件允许用户搜索电影名称,我正在调用 API 向他展示所有相应的电影。
这是我的类组件:
class Search extends React.Component {
constructor(props) {
super(props);
this.searchedText = "";
this.page = 0
this.totalPages = 0
this.state = {
films: [],
isLoading: false
}
}
_loadFilms() {
if (this.searchedText.length > 0) {
this.setState({ isLoading: true })
getFilmsFromApiWithSearchedText(this.searchedText, this.page+1).then(data => {
this.page = data.page
this.totalPages = data.total_pages
this.setState({
films: [ ...this.state.films, ...data.results ],
isLoading: false
})
})
}
}
_searchTextInputChanged(text) {
this.searchedText = text
}
_searchFilms() {
this.page = 0
this.totalPages = 0
this.setState({
films: [],
}, () => {
this._loadFilms()
})
}
render() {
return (
<View style={styles.main_container}>
<TextInput
style={styles.textinput}
placeholder='Titre du film'
onChangeText={(text) => this._searchTextInputChanged(text)}
onSubmitEditing={() => this._searchFilms()}
/>
<Button title='Rechercher' onPress={() => this._searchFilms()}/>
<FlatList
data={this.state.films}
keyExtractor={(item) => item.id.toString()}
renderItem={({item}) => <FilmItem film={item}/>}
onEndReachedThreshold={0.5}
onEndReached={() => {
if (this.page < this.totalPages) {
this._loadFilms()
}
}}
/>
</View>
)
}
}
render() {
return (
<View>
<TextInput
onChangeText={(text) => this._searchTextInputChanged(text)}
onSubmitEditing={() => this._searchFilms()}
/>
<Button title='Search' onPress={() => this._searchFilms()}/>
<FlatList
data={this.state.films}
keyExtractor={(item) => item.id.toString()}
renderItem={({item}) => <FilmItem film={item}/>}
onEndReachedThreshold={0.5}
onEndReached={() => {
if (this.page < this.totalPages) {
this._loadFilms()
}
}}
/>
{this._displayLoading()}
</View>
)
}
}
如何使用钩子翻译以下内容:
this.page
和this.totalPages
?useRef 是解决方案吗?当我的电影列表为空时(因为这是一个新的搜索) ,
_searchFilms()
我正在使用setState
回调进行新的 API 调用。setState
但是因为是异步的,所以在之后立即执行是行不通的。但我找不到用钩子做的方法。
我认为useEffect
可以这样做,但是:
- 我只想在我的
film
列表为空时进行此 API 调用,因为我要求_searchFilms()
进行新的搜索。 _loadFilms()
this.films
在用户滚动时调用以向 FlatList 添加更多电影(用于相同的搜索),因此在这种情况下我无法清除。
这是我到目前为止的翻译方式:
const Search = () => {
const [searchText, setSearchText] = useState('');
const [films, setFilms] = useState([]);
// handle pagination
const page = useRef(0);
const totalPages = useRef(0);
// handle api fetch
const [isLoading, setIsLoading] = useState(false);
const loadFilmsFromApi = () => {
getFilmsFromApiWithSearchedText(searchText, page + 1).then((data) => {
page.current = data.page;
totalPages.current = data.total_pages;
setFilms(films => [...films, ...data.results]);
setIsLoading(false);
})
};
const searchFilm = () => {
if (searchText.length > 0) {
page.current = 0;
totalPages.current = 0;
setFilms([]);
// HERE MY Films list won't be cleared (setState asynchronous)
loadFilmsFromApi();
// after the api call, clear input
setSearchText('');
}
};
useEffect(() => {
console.log(page, totalPages, "Film number" + films.length);
}, [films]);
解决方案
我认为你走在正确的道路上。至于totalPages
and page
,如果您想在不同的渲染之间保持该值(设置状态时),将其作为一个ref
有意义的
const Search = () => {
const [searchText, setSearchText] = useState('');
const [films, setFilms] = useState([]);
// handle pagination
const page = useRef(0);
const totalPages = useRef(0);
// handle api fetch
const [isLoading, setIsLoading] = useState(false);
// This can be invoked by either search or user scroll
// When pageNum is undefined, it means it is triggered by search
const loadFilmsFromApi = (pageNum) => {
console.log("APPEL", 'loadFills');
getFilmsFromApiWithSearchedText(searchText, pageNum ? pageNum + 1 : 1).then((data) => {
page.current = data.page;
totalPages.current = data.total_pages;
setFilms(films => {
if(pageNum) {
return [...films, ...data.results];
} else {
return [data.results];
}
});
setIsLoading(false);
})
};
useEffect(() => {
if (searchText.length > 0) {
page.current = 0;
totalPages.current = 0;
setFilms([]);
loadFilmsFromApi();
// after the api call, clear input
setSearchText('');
}
}, [searchText, loadFilmsFromApi]);
useEffect(() => {
console.log(page, totalPages, "Nombre de film " + films.length);
}, [films]);
return ( <
div > Search < /div>
);
};
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
推荐阅读
- nginx - nginx lua body_filter_by_lua_block 需要在 content_by_lua 的上下文中执行 sleep API disabled*
- guice - 如何绑定动态@Named 绑定
- abap - 形参个数大于实参个数
- javascript - 在角度项目中的数组上设置间隔
- python - 在 localhost 打开但永远保持空白的地方使用 vpython 时出现问题
- scala - Scala 跨项目中的资源
- django - 如何在 django 查询中将表单中的日期与 db 中的日期进行比较?
- django - 在具有嵌套资源的 Tastypie 中,对于给定的 url,获取视图函数名称的最佳方法是什么?
- php - Yii:尽管安装了 memcache/memcached,CMemCache 仍需要加载 PHP memcache 扩展
- python - Python pkg_resources 找不到模块