I am currently building a simple web using react with redux. I have successfully integrated redux with app however I get 2 issue that I am unable to work out. The first issue is that when the user apply the filter and then trigger the request the component keep rendering exceeding the limit.
The second issue is that when the user change the page the first click the request give a page markup but with the second click everything works.
These are my code so far.
action that take care of the request
import { BEGIN_FETCH_MOVIES, FETCHED_MOVIES, FETCH_FAILED_MOVIES } from '../constants';
import axios from 'axios';
//fetch movie
const searchQuery = (url) => {
return dispatch => {
//dispatch begin fetching
dispatch({
type : BEGIN_FETCH_MOVIES,
})
//make a get request to get the movies
axios.get(url)
.then((res) => {
//dispatch data if fetched
dispatch({type : FETCHED_MOVIES, payload : res.data});
})
.catch((err) => {
//dispatch error if error
dispatch({type : FETCH_FAILED_MOVIES});
});
}
//return the result after the request
}
export default searchQuery;
Main component
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { actionSearchMovie, actionSearchSerie } from '../actions'
import DisplayItemMovie from '../components/DisplayItemMovie';
import DisplayItemSerie from '../components/DisplayItemSerie';
import DrPagination from "../components/DrPagination";
import { Layout, Divider, Icon, Spin, Row } from 'antd';
//Home component
class Home extends Component {
constructor(){
super();
this.state = {
moviePage : 1,
seriePage : 1,
urlMovie : '',
urlSerie : ''
}
}
//make request before the render method is invoked
componentWillMount(){
//url
const discoverUrlMovies = 'https://api.themoviedb.org/3/discover/movie?api_key=72049b7019c79f226fad8eec6e1ee889&language=en-US&sort_by=popularity.desc&include_adult=false&include_video=false&page=1';
//requests
this.fetchMovie(discoverUrlMovies);
}
fetchMovie = ( url ) => {
this.props.actionSearchMovie(url);
}
//handle pagination
handleChangePage = (page) =>{
let url = 'https://api.themoviedb.org/3/discover/movie?api_key=72049b7019c79f226fad8eec6e1ee889&language=en-US&sort_by=popularity.desc&include_adult=false&include_video=false&page=' + page;
this.setState({
moviePage : page,
urlMovie : url
}, ()=> this.state);
this.fetchMovie(this.state.urlMovie);
}
//render
render() {
const movies = this.props.movies.results; //movies
let displayMovies; //display movies
const antIcon = <Icon type="loading" style={{ fontSize: 24 }} spin />; //spinner
//if movies and series is undefined, display a spinner
if(movies.results === undefined){
displayMovies = <Spin indicator={antIcon} />
}else {
//map through movies and series and then display the items
displayMovies = movies.results.map((movie) => {
return <DisplayItemMovie key = {movie.id} movie = {movie} />
});
}
return (
<div>
<div className='header'>
Home
</div>
<Divider />
<Layout style = {{paddingBottom : '1rem', margin : '0 auto' }}>
<h1 className = 'title'>Movie</h1>
<Row type = 'flex' style = {{flexWrap : 'wrap'}}>
{displayMovies}
</Row>
<DrPagination total = { movies.total_results } page = { this.handleChangePage } currentPage = { this.state.moviePage } /> </div>
)
}
};
const mapStateToProps = (state) => {
return{
movies : state.search_movies,
}
}
export default connect(mapStateToProps, { actionSearchMovie })(Home);
Filter component
i
mport React, { Component } from 'react';
import { Row, Col, Select, Button, Divider, InputNumber } from 'antd';
//official genres by movie db
const genres = [
{
"id": 28,
"name": "Action"
},
{
"id": 12,
"name": "Adventure"
}
];
class Filter extends Component {
constructor () {
super();
this.state = {
genre : [],
year : '',
rate : '',
filter : false,
}
}
//handle Genre
handleGenre = (genre) => {
console.log(genre);
this.setState({
genre
}, () => this.state);
}
//handle year
handleYear = (year) => {
this.setState({
year
}, () => this.state);
}
//handle Vote
handleVote = (rate) =>{
this.setState({
rate
}, ()=> this.state);
}
//handle on filter
handleFilter = () =>{
const { genre, year, rate } = this.state;
let url = 'https://api.themoviedb.org/3/discover/movie?api_key=72049b7019c79f226fad8eec6e1ee889&language=en-US&page=1';
if( genre.length === 0 && rate === "" && year === "" ){
alert('No filter is selected');
}else{
this.setState({
filter : true
});
let genreList = '';
if(genre.length > 0){
genreList = '&with_genres='+genre.join();
url += genreList;
}
if(year !== ""){
url += '&primary_release_year='+year;
}
if(rate !== ""){
url += '&vote_average='+rate;
}
//if filter === true pass the new url to the parent component
this.props.url(url);
}
}
render() {
const {filter} = this.state;
let header;
const displayGenres = genres.map((genre) => {
return (
<Select.Option key = { genre.id }>{genre.name}</Select.Option>
);
});
//
if(filter === false){
header = <h1>Top Movies</h1>
}else{
header = <h1>Custom Search</h1>
}
return (
<div>
{header}
<Divider />
<Row type = 'flex' align = 'middle' justify = 'center'>
<Col span = {14}>
<Row type = 'flex' align = 'middle' justify = 'center'>
<Col span = {5}>
<Select
mode = 'tags'
maxTagCount = {1}
style = {{width : '100%'}}
allowClear
placeholder="All Genre"
onChange = {this.handleGenre}
>
{displayGenres}
</Select>
</Col>
<Col span = {3}>
<Select
maxTagCount = {1}
style = {{width : '100%'}}
allowClear
placeholder="All Rate"
onChange = {this.handleVote}
>
<Select.Option value = '5'>>5</Select.Option>
<Select.Option value = '6'>>6</Select.Option>
<Select.Option value = '7'>>7</Select.Option>
<Select.Option value = '8'>>8</Select.Option>
<Select.Option value = '9'>>9</Select.Option>
</Select>
</Col>
<Col span = {3}>
<InputNumber
min = {1980}
max = {2019}
placeholder = 'All Year'
onChange = {this.handleYear}
/>
</Col>
</Row>
</Col>
<Col span = {5}>
<Button type = 'ghost' onClick = {this.handleFilter}>Filter</Button>
</Col>
</Row>
</div>
)
}
};
export default Filter;
Pagination component
import React, { Component } from 'react';
import { Pagination } from 'antd';
export default class DrPagination extends Component {
//on change page set the new page
handleChangePage = (page) =>{
this.props.page(page);
}
render() {
return (
<div style = {styles.container}>
<Pagination
current = {this.props.currentPage}
defaultCurrent = {1}
total = {this.props.total}
defaultPageSize = {20}
onChange = {this.handleChangePage}
size = 'small'
showQuickJumper
/>
</div>
)
}
};
const styles = {
container : {
width : '100%',
margin: '1rem',
display: 'flex',
justifyContent: 'center',
alignContent: 'center',
alignItems: 'center',
}
}
This is the data that I get when I try to change the page (it happen only for the first time).