@Ekaterina4321

Почему Context.Consumer не обновляется при изменениях в Context.Provider?

У меня есть веб-приложение, которое ходит к API БД фильмов. В SideBar отображены фильтры поиска фильмов, по кнопке поиска с выбранными параметрами(жанр, год и т.д.) отправляет запрос к API. Вот так выглядит приложение(слева SideBar, справа Home, в котором лежит Movie):
5df3f26c14187832945652.png
Для передачи данных использую 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. если не достаточно деталей или наоборот слишком много, прошу прощения, первый мой вопрос :)
  • Вопрос задан
  • 65 просмотров
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы