首页 > 解决方案 > 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>
        )
    }
}

如何使用钩子翻译以下内容:

我认为useEffect可以这样做,但是:

这是我到目前为止的翻译方式:

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

标签: reactjsreact-nativereact-hooksuse-effect

解决方案


我认为你走在正确的道路上。至于totalPagesand 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>


推荐阅读