Подождите, пока браузер отобразит элемент в React

#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 }))); . Большое вам спасибо за вашу помощь!