React Native hooks, useRef and 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.pagethis.totalPages?useRef是解决方案吗?

  • _searchFilms()中,当我的电影列表为空时(因为这是一个新的搜索(,我使用setState回调来进行新的API调用。但是,由于setState是异步的,所以在之后立即执行是不起作用的。但我找不到用钩子做这件事的方法。

我认为useEffect可以做到这一点,但:

  • 我只想在film列表为空时进行此API调用,因为我调用_searchFilms()进行新搜索
  • _loadFilms()在用户滚动时被调用,以将更多影片添加到平面列表(用于相同的搜索(,因此在这种情况下我无法清除this.films

以下是我迄今为止的翻译方式:

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]);

我认为你走的是正确的道路。至于totalPagespage,如果您想在不同的渲染(设置状态时(之间保持该值,那么将其作为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>

不完全清楚你的问题是什么,但听起来你想在向api发出查询之前清除电影状态?我也不清楚useRef在这里的使用——useRef只是一种获取元素引用的方法,所以以后很容易访问它——比如获取div引用,并能够通过myDivRef.current轻松访问它

const = myDivRef = useRef;
...
<div ref={myDivRef}/>

如果是这样的话,那么我只需要在API调用返回时设置一次电影的状态。WRT对refs来说,这似乎只是正常变量,或者函数中可能的状态项。

更新:在这里清除目标后,您可以简单地向loadFilmsFromApi添加一个参数,以确定是否应该附加或覆盖:

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);
})
};

最新更新