#javascript #css #reactjs
Вопрос:
Я использую CSS transition
с top
и left
для анимации движения элемента в React.
Для достижения этой цели компонент сначала должен быть отрисован с top: 0; left: 0
помощью, а затем повторно отрисован с измененными top
и left
свойствами , чтобы начать переход.
Это мой компонент:
export default class Animator extends React.Component{
render(){
var top = 0;
var left = 0;
if(this.state.moving){
top = this.props.top;
left = this.props.left;
}
return(
<div
className="red-box animator"
style={{
top: `{top}px`,
left: `{left}px`}}>
</div>
);
}
componentDidMount(){
this.setState({moving: true});
}
}
.animator{
position: absolute;
transition: top 0.5s, left 0.5s;
}
.red-box{
width: 50px;
height: 50px;
background-color: red;
}
Я ожидал, что компонент будет отображаться браузером перед componentDidMount
запуском, но обнаружил, что это не так.
В результате свойства top
и left
обновляются слишком рано, и компонент немедленно появляется в целевом положении без перехода.
Изменение моей функции componentDidMount на задержку решает проблему, но слишком малая задержка делает функциональность ненадежной (особенно на более медленных устройствах), и я не хочу более длительной задержки, так как я хочу, чтобы элемент перемещался, как только он появится на экране.
componentDidMount(){
setTimeout(() => {
this.setState({moving: true});
}, 150);
}
Есть ли способ гарантировать, что я обновлю состояние только после того, как браузер отобразит элемент?
Ответ №1:
Браузеры оптимизируют рендеринг и не повторяют то, что изменилось в одном и том же кадре анимации. Они объединяют изменения и отображают конечный результат. Чтобы смягчить это, вы можете использовать requestAnimationFrame
трюк:
componenetDidMount() {
self.requestAnimationFrame(() => this.setState({ moving: true })
}
Имейте в виду, что, хотя requestAnimationFrame
он широко поддерживается среди браузеров, некоторым действительно старым браузерам может потребоваться заполнение или префикс, чтобы он работал.
Комментарии:
1. Использование вашего примера не устранило проблему в React, но я обнаружил, что если я добавил дополнительный вызов requestAnimationFrame, то проблема была надежно решена. Мой окончательный код в componentDidMount таков:
requestAnimationFrame(() => requestAnimationFrame(() => this.setState({ moving: true })));
. Большое вам спасибо за вашу помощь!