У меня есть веб-приложение, которое ходит к API БД фильмов. В SideBar отображены фильтры поиска фильмов, по кнопке поиска с выбранными параметрами(жанр, год и т.д.) отправляет запрос к API. Вот так выглядит приложение(слева SideBar, справа Home, в котором лежит Movie):
Для передачи данных использую React Context.
Код App.js (в нем Context.Provider):
class App extends Component {
constructor(props) {
super(props);
this.state = {
year: '',
genre: '',
country: '',
allGenres: {},
genreId: '',
filter: this.filter
};
}
filter = (year, country, genre, genreId) => {
this.setState(state => ({
...state,
filter: this.filter
}));
};
render() {
return (
<div className="App">
<header className="App-header">
<MovieContext.Provider value={this.state}>
<Home/>
</MovieContext.Provider>
</header>
</div>
);
}
}
export default (App);
Код Home.js:
function Home(props) {
return (
<div className={classes.root}>
<SideBar/>
<main>
<Movie/>
</main>
</div>
);
}
export default withStyles({withTheme: true})(Home);
Код SideBar.js (в нем Context.Consumer, в который обернута кнопка Search, по нажатию на которую отправляю запрос):
function SideBar(props) {
const [open, setOpen] = useState(true);
const [state, setState] = React.useState({
year: '',
genre: '',
country: '',
allGenres: {},
genreId: ''
});
const handleChange = name => event => {
setState({
...state,
[name]: event.target.value,
});
};
const handleChangeGenre = name => event => {
setState({
...state,
[name]: event.target.value,
genreId: event.target.selectedOptions[0].getAttribute('id')
});
};
var apiKey = "blablabla";
useEffect(() => {
fetch(`url`, {
"method": "GET",
"headers": {
"Accept": "application/json"
}
})
.then(response =>
response.ok ? response : Promise.reject(response)
)
.then(response =>
response.json()
)
.then(json => {
setState(state => ({
...state,
allGenres: json
}));
})
.catch(err => {
console.log(err);
});
}, []);
const genreRender = () => {
var genres = state.allGenres.genres;
if (genres) {
return genres.map((genre, id) => {
return (
<option key={id} id={genre.id} value={genre.name}>{genre.name}</option>
)
});
} else return null;
};
const searchMovie = (filter) => {
var year = state.year;
var genre = state.genre;
var genreId = state.genreId;
var country = state.country;
filter(year, genre, genreId, country);
fetch(`url`, {
"method": "GET",
"headers": {
"Accept": "application/json"
}
})
.then(response =>
response.ok ? response : Promise.reject(response)
)
.then(response =>
response.json()
)
.then(json => {
console.log(json);
})
.catch(err => {
console.log(err);
});
};
return (
<div className={classes.root}>
<AppBar position="fixed">
<Toolbar>
<div className={classes.sectionDesktop}>
<IconButton>
<FavoriteIcon/>
</IconButton>
</div>
</Toolbar>
</AppBar>
<Drawer
open={open}
>
<div className={classes.toolbar}>
<Typography className={classes.title} variant="h6" noWrap>
Filters
</Typography>
</div>
<Divider/>
<FormControl variant="outlined" className={classes.formControl}>
<InputLabel ref={inputLabel} htmlFor="outlined-age-native-simple">
Genre
</InputLabel>
<Select
native
value={state.genre}
onChange={handleChangeGenre('genre')}
labelWidth={labelWidth}
inputProps={{
name: 'genre',
id: 'outlined-age-native-simple',
}}
>
<option value=""/>
{genreRender()}
</Select>
</FormControl>
<MovieContext.Consumer>
{({genre, year, genreId, country, filter}) => (
<FormControl variant="outlined" className={classes.formControl}>
<InputLabel ref={inputLabel} htmlFor="outlined-age-native-simple">Year</InputLabel>
<Select
value={state.year}
onChange={handleChange('year')}
labelWidth={labelWidth}
inputProps={{
name: 'age',
id: 'outlined-age-native-simple',
}}
>
<option value=""/>
<option value={2017}>2017</option>
<option value={2018}>2018</option>
<option value={2019}>2019</option>
</Select>
</FormControl>
)}
</MovieContext.Consumer>
<FormControl variant="outlined" className={classes.formControl}>
<InputLabel ref={inputLabel} htmlFor="outlined-age-native-simple">Country</InputLabel>
<Select
value={state.country}
onChange={handleChange('country')}
labelWidth={labelWidth}
inputProps={{
name: 'age',
id: 'outlined-age-native-simple',
}}
>
<option value=""/>
<option value="USA">USA</option>
<option value="UK">UK</option>
<option value="France">France</option>
</Select>
</FormControl>
<MovieContext.Consumer>
{({genre, year, genreId, country, filter}) => (
<div className={classes.divBtn}>
<Button className={classes.Btn} variant="contained" onClick={() => searchMovie(filter)}>
search
</Button>
</div>
)}
</MovieContext.Consumer>
<Typography className={classes.cr}>Copyright © 2019 KatushkaEsina</Typography>
<Typography className={classes.cr2}>All rights reserved</Typography>
</Drawer>
</div>
);
}
export default withStyles({withTheme: true})(SideBar);
Код Movie.js (в нем Context.Consumer, в который обернут весь компонент фильма - , в котором я и пытаюсь получить название фильма, но пока что просто год из фильтра):
function Movie() {
return <MovieContext.Consumer>
{({genre, year, genreId, country, filter}) => (
<div className={classes.root}>
<Paper className={classes.paper}>
<Grid container spacing={2}>
<Grid item>
<ButtonBase className={classes.image}>
<img className={classes.img} alt="moviePoster" src={logo} style={{width: 120, height: 120}}/>
</ButtonBase>
</Grid>
<Grid item xs={12} sm container>
<Grid item xs container direction="column" spacing={2}>
<Grid item xs>
<Typography gutterBottom variant="subtitle1">
{year || 'Movie name'}
</Typography>
<Typography variant="body2" gutterBottom>
Movie description
</Typography>
<Typography variant="body2" color="textSecondary">
Movie genre
</Typography>
</Grid>
<Grid item>
<Typography variant="body2" style={{ cursor: 'pointer' }}>Snow more info</Typography>
</Grid>
</Grid>
</Grid>
</Grid>
</Paper>
</div>
)}
</MovieContext.Consumer>
}
export default withStyles({withTheme: true})(Movie);
Сам контекст:
export const MovieContext = React.createContext({
genre: '',
country: '',
year: '',
genreId: '',
filter: (genre, country, year, genreId) => {
this.genre = genre || '';
this.country = country || '';
this.year = year;
this.genreId = genreId || '';
},
});
Проблема в том, что когда я выбираю из фильтров нужные, нажимаю на кнопку и отправляю запрос, в компоненте фильма (Movie.js), в Typography остается текст, а не год, который я выбираю в фильтре({year || 'Movie name'}). Подскажите, пожалуйста, что не так делаю?
P.S. если не достаточно деталей или наоборот слишком много, прошу прощения, первый мой вопрос :)