У меня есть компонент ShowcaseMov ie, который извлекает данные на componentDidMount()
и устанавливает их в состояние. Компонент отображает компоненты карты для отображения данных, а также четырех элементов кнопок upcoming
, top_rated
, popular
и now_playing
, которые позволяют пользователю переключаться между соответствующими данными. Каждая кнопка имеет событие onClick, которое вызывает changeFilter
и устанавливает состояние currentFilter
для выбранной клавиши.
Проблема: при нажатии кнопок фильтра иногда страница переходит наверх (если это не так). уже здесь). Я пытался найти решения для этого, но я не могу понять, что происходит. Любые предложения будут очень полезны, заранее спасибо.
Обновление: эта проблема возникает, когда не задана высота для элемента с dynamici c children. Если я установлю высоту ShowcaseMov ie на что-то большое, например height: 200vh
, оно исчезнет.
Я думаю, что я решил свою проблему, но хотел бы услышать другие мысли о том, почему это происходит, и некоторые другие способы это исправить. Трудно установить высоту для родителя, когда вы не знаете, сколько контента будет отображаться (или высота этого контента). min-height
помогло бы, но все равно это было бы быстро исправить.
ShowcaseMov ie. js
import React, { Component } from "react";
import Card from "./Card";
import "../css/ShowcaseMovie.css";
import { v4 as uuidv4 } from "uuid";
import { formatString, buildMovieState } from "../utilities";
class ShowcaseMovie extends Component {
static defaultProps = {
filterNames: ["upcoming", "popular", "now_playing", "top_rated"]
};
constructor(props) {
super(props);
this.state = {
upcoming: [],
now_playing: [],
popular: [],
top_rated: [],
currentFilter: this.props.filterNames[0]
};
}
changeFilter = e => {
e.preventDefault();
const type = e.target.name;
this.setState({ currentFilter: type });
};
componentDidMount() {
this.props.filterNames.map(name => this.fetchMovies(name));
// setInterval(() => {
// this.timeoutFilter();
// }, 10000);
}
async fetchMovies(type) {
try {
const res = await fetch(
`url`
);
const data = await res.json();
if (data) {
this.setState(state => ({
...state,
[type]: buildMovieState(data)
}));
}
} catch (error) {
console.log(error);
}
}
render() {
const { currentFilter } = this.state;
const movies = this.state[currentFilter].map((movie, i) => (
<Card key={uuidv4()} movie={movie} index={i} />
));
const buttons = this.props.filterNames.map(name => (
<button
type="button"
key={name}
name={name}
className={`ShowcaseMovie-btn ${
currentFilter === name ? "active" : ""
}`}
disabled={currentFilter === name}
onClick={this.changeFilter}>
{formatString(name)}
</button>
));
return (
<section className="ShowcaseMovie">
<div className="ShowcaseMovie-container">
<h2 className="ShowcaseMovie-header">Movies</h2>
<div className="ShowcaseMovie-btn-container">{buttons}</div>
</div>
<div className="ShowcaseMovie-grid">{movies}</div>
</section>
);
}
}
ShowcaseMov ie. css
.ShowcaseMovie {
padding: 4rem 10%;
}
.ShowcaseMovie-container {
position: relative;
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 2rem;
}
.ShowcaseMovie-button-container {
display: flex;
justify-content: center;
align-items: center;
}
.ShowcaseMovie-container::after {
content: "";
background-color: #64b5f6;
height: 80%;
width: 6px;
left: 0;
position: absolute;
border-radius: 1px;
}
.ShowcaseMovie-header {
font-size: 3rem;
font-weight: 200;
margin: 0 5rem;
}
.ShowcaseMovie-btn {
outline: none;
border: none;
background-color: transparent;
font-size: 1.6rem;
font-weight: 500;
letter-spacing: 1px;
padding: 1rem;
margin-left: 4rem;
color: white;
opacity: 0.5;
cursor: pointer;
transition-property: opacity;
transition-duration: 300ms;
transition-timing-function: ease;
}
.ShowcaseMovie-btn:hover {
opacity: 1;
transition-property: opacity;
transition-duration: 300ms;
transition-timing-function: ease;
}
.ShowcaseMovie-btn.active {
opacity: 1;
cursor: auto;
color: #64b5f6;
}
.ShowcaseMovie-grid {
display: grid;
gap: 3rem;
grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
}
Карта. js
import React, { Component } from "react";
import "../css/Card.css";
class Card extends Component {
render() {
const { title, poster_path } = this.props.movie;
const style = { animationDelay: `${80 * this.props.index}ms` };
return (
<div className="Card">
<div className="Card-inner" style={style}>
<img
src={`https://image.tmdb.org/t/p/w500/${poster_path}`}
alt=""
className="Card-img"
/>
<p className="Card-name">{title}</p>
</div>
</div>
);
}
}
export default Card;
Карта. css
.Card {
display: block;
transition: transform 300ms ease;
}
.Card:hover {
transform: translateY(-5px);
transition: transform 300ms ease;
}
.Card-inner {
position: relative;
display: block;
cursor: pointer;
height: 100%;
opacity: 0;
animation-name: moveUp;
animation-duration: 500ms;
animation-delay: 50ms;
animation-timing-function: ease;
animation-fill-mode: forwards;
}
.Card-inner::after {
content: "";
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-image: linear-gradient(transparent, rgba(33, 47, 61, 0.8));
border-bottom-left-radius: 2px;
border-bottom-right-radius: 2px;
z-index: 100;
opacity: 1;
transition: opacity 300ms ease;
}
.Card-inner:hover::after {
opacity: 0;
transition: opacity 300ms ease;
}
.Card-inner::before {
content: "";
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-image: linear-gradient(transparent, rgba(100, 180, 246, 0.6));
border-bottom-left-radius: 2px;
border-bottom-right-radius: 2px;
z-index: 100;
opacity: 0;
transition: opacity 300ms ease;
}
.Card-inner:hover::before {
opacity: 1;
transition: opacity 300ms ease;
}
.Card-img {
display: block;
position: relative;
object-fit: cover;
max-width: 100%;
min-height: 100%;
z-index: 0;
border-radius: 2px;
}
.Card-name {
position: absolute;
bottom: 0;
left: 0;
margin: 0 2rem 2rem 2rem;
z-index: 150;
font-weight: 400;
text-transform: uppercase;
font-size: 1.4rem;
letter-spacing: 2px;
}
@keyframes moveUp {
0% {
transform: translateY(5rem);
}
100% {
transform: translateY(0);
opacity: 1;
}
}
коммунальные услуги. js
export const formatString = name => {
return name
.replace("_", " ")
.split(" ")
.map(w => w[0].toUpperCase() + w.slice(1))
.join(" ");
};
export const buildMovieState = data => {
if (data.results) {
const movies = data.results.filter(
d => d.backdrop_path && d.id && d.title && d.poster_path
);
return movies.length > 10 ? movies.slice(0, 10) : movies;
} else {
return [];
}
};