[英]React Native hooks, useRef and useEffect
I'm trying to translate a Class Component into a Functional one with React Native.我正在尝试将Class 组件转换为具有 React Native 的功能性组件。
My Search
component lets the user search for a film name and I'm making an API call to show him all corresponding films.我的Search
组件让用户搜索电影名称,我正在调用 API 向他展示所有相应的电影。
Here is my class component:这是我的 class 组件:
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>
)
}
}
How can I translate the following with hooks:如何使用钩子翻译以下内容:
this.page
and this.totalPages
? this.page
和this.totalPages
? is useRef the solution? useRef 是解决方案吗?
in _searchFilms()
I'm using setState
callback to make a new API call when my film list is empty (because it's a new search).在_searchFilms()
中,当我的电影列表为空时(因为这是一个新搜索),我正在使用setState
回调进行新的 API 调用。 But doing it right after doesn't work because setState
is asynchronous.但是因为setState
是异步的,所以在之后立即执行它是行不通的。 But I can't find a way to do it with hooks.但我找不到用钩子做的方法。
I think useEffect
could do this but:我认为useEffect
可以做到这一点,但是:
film
list is empty, because I call _searchFilms()
for a new search .我只想在我的film
列表为空时进行此 API 调用,因为我调用_searchFilms()
进行新搜索。_loadFilms()
is called on user scroll to add more films to the FlatList (for the same search) so I can't clear this.films
in this case. _loadFilms()
在用户滚动时被调用以向 FlatList 添加更多电影(用于相同的搜索),因此在这种情况下我无法清除this.films
。Here is how I translated it so far:到目前为止,我是这样翻译的:
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]);
I think you are on the right path.我认为你走在正确的道路上。 As for totalPages
and page
, having it as a ref
makes sense if you want to maintain that values between different renders ( when setting state )至于totalPages
和page
,如果您想在不同的渲染之间保持该值(设置 state 时),将其作为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>
Not totally clear what your question is, but it sounds like you want to clear films state before you fire off the query to the api?不完全清楚你的问题是什么,但听起来你想在向 api 发起查询之前清除电影 state? I am also not clear on the use of useRef here - useRef is simply a way to get a reference to an element so it's easy to access it later - like get a reference to a div and be able to access it easily via myDivRef.current
我也不清楚 useRef 在这里的使用 - useRef只是一种获取元素引用的方法,因此以后很容易访问它 - 比如获取对 div 的引用并能够通过myDivRef.current
轻松访问它
const = myDivRef = useRef;
...
<div ref={myDivRef}/>
If that is the case, then I would simply set the state of films once in the return of the API call.如果是这种情况,那么我只需在 API 调用的返回中设置一次电影的 state。 WRT to the refs, it seems like you this should just be normal variables, or possible state items in your function. WRT 给裁判,看起来你这应该只是普通变量,或者你的 function 中可能的 state 项目。
UPDATE : After clearing up the goal here, you could simply add a parameter to loadFilmsFromApi
to determine if you should append or overwrite:更新:在这里清除目标后,您可以简单地向loadFilmsFromApi
添加一个参数以确定您是否应该 append 或覆盖:
const loadFilmsFromApi = (append) => {
getFilmsFromApiWithSearchedText(searchText, page + 1).then((data) => {
page.current = data.page;
totalPages.current = data.total_pages;
if (append) {
setFilms({
films: this.state.films.concat(data.results)
});
} else {
setFilms({
films: data.results
});
}
setIsLoading(false);
})
};
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.