Сравнение производительности между перехватчиками реакции и классом реакции

#javascript #reactjs

#javascript #reactjs

Вопрос:

Я пытаюсь изучить перехватчики react. Мне нужна помощь в понимании того, всегда ли функции react сбрасывают состояние перехвата при каждом рендеринге.

Вот небольшой пример прокрутки, в котором я пытаюсь исправить заголовок

 class Header extends Component {


    constructor(props) {
        super(props);
        console.log("Constructor")
        this.state = {fixed: false};
    }


    handleScroll = () => {
        console.log(window.scrollY);
        console.log(this.state.fixed);
        if (window.scrollY >= 25 amp;amp; !this.state.fixed) {
            this.setState({
                fixed: true
            });
        } else if(window.scrollY < 25 amp;amp; this.state.fixed){
            this.setState({
                fixed: false
            });
        }
    }

    componentDidUpdate(prevProps, prevState, snapshot) {
        console.log("updated ");
    }

    componentDidMount() {
        console.log("added");
        window.addEventListener('scroll', this.handleScroll);
    }

    componentWillUnmount() {
        console.log("removed");
        window.removeEventListener('scroll', this.handleScroll);
    }

    render() {
        return (
            <div></div>
        );
   }
}
  

Вывод:

 Header.js:26 Constructor
Header.js:51 added
Header.js:32 1
Header.js:33 false
Header.js:32 2
Header.js:33 false
Header.js:32 5
Header.js:33 false
Header.js:32 9
Header.js:33 false
Header.js:32 15
Header.js:33 false
Header.js:32 20
Header.js:33 false
Header.js:32 26
Header.js:33 false
Header.js:47 updated 
Header.js:32 31
Header.js:33 true
Header.js:32 35
Header.js:33 true
Header.js:32 38
Header.js:33 true
Header.js:32 40
Header.js:33 true
Header.js:32 39
Header.js:33 true
Header.js:32 38
Header.js:33 true
Header.js:32 35
Header.js:33 true
Header.js:32 31
Header.js:33 true
Header.js:32 25
Header.js:33 true
Header.js:32 20
Header.js:33 true
Header.js:47 updated 
Header.js:32 9
Header.js:33 false
Header.js:32 5
Header.js:33 false
Header.js:32 2
Header.js:33 false
Header.js:32 0
Header.js:33 false
  

Это работает нормально.

Теперь с реактивными крючками та же логика. Я просто пытаюсь посмотреть на поведение состояния FixedHeader.

 const Header = props => {

    console.log("rendering");
    const [FixedHeader, setFixedHeader] = useState(false);

    useEffect(() => {
        document.addEventListener("scroll", () => {
            console.log(window.scrollY);
            console.log(FixedHeader);
            if (window.scrollY >= 30) {
                setFixedHeader(true);
            } else {
                setFixedHeader(false);
            }
        })
    }, []);


    return (
        <div></div>
   );
}
  

Вывод:

 Header.js:23 rendering
Header.js:28 1
Header.js:29 false
Header.js:28 2
Header.js:29 false
Header.js:28 5
Header.js:29 false
Header.js:28 9
Header.js:29 false
Header.js:28 15
Header.js:29 false
Header.js:28 20
Header.js:29 false
Header.js:28 26
Header.js:29 false
Header.js:28 31
Header.js:29 false
Header.js:23 rendering
Header.js:28 35
Header.js:29 false
Header.js:23 rendering
Header.js:28 38
Header.js:29 false
Header.js:28 40
Header.js:29 false
Header.js:28 39
Header.js:29 false
Header.js:28 38
Header.js:29 false
Header.js:28 35
Header.js:29 false
Header.js:28 31
Header.js:29 false
Header.js:28 25
Header.js:29 false
Header.js:23 rendering
Header.js:28 20
Header.js:29 false
Header.js:23 rendering
Header.js:28 14
Header.js:29 false
Header.js:28 9
Header.js:29 false
Header.js:28 5
Header.js:29 false
Header.js:28 2
Header.js:29 false
Header.js:28 0
Header.js:29 false
  

Я не могу понять это поведение, почему рендеринг вызывается дважды, а значение FixedHeader равно false, даже если scroll >= 30.

Я новичок в js, поэтому я думаю, что именно так рендеринг работы функции выполняется 2 раза, потому что функция вызывалась дважды, но почему дважды, и каждый раз, когда вызывается функция, все состояния нужно устанавливать заново, не повлияет ли это на производительность (я могу ошибаться).

Примечание: я не добавил html-часть, это простой заголовок, в который я добавляю класс «fixed-top» на основе логической переменной.

Комментарии:

1. Вы переходите [] к useEffect , что означает, что код выполняется только при первом отображении компонента. В этот момент FixedHeader имеет значение false . Каждый раз, когда компонент отображает, создается новая FixedHeader переменная.

2. OMG вопрос о фактической производительности фактического кода вместо предположений без загрузки. 1 вам!

3. @FelixKling означает ли это более низкую производительность по сравнению с class.

4. Если вы имеете в виду, занимает ли добавление и удаление обработчика событий каждый раз при изменении значения больше времени, чем не делать этого, тогда да 😉 Я сомневаюсь, что это окажет какое-либо ощутимое влияние.

5. @FelixKling я имею в виду, что вы сказали: «Каждый раз, когда компонент отображает новую переменную FixedHeader, создается». так что, если у вас много состояний, это может быть проблемой.

Ответ №1:

Я не могу понять это поведение, почему рендеринг вызывается дважды, а значение FixedHeader равно false, даже если scroll >= 30.

Я предполагаю, что из-за закрытия функции была создана функция запоминания значения FixedHeader, которое у нее было в данный момент… вы можете создать некоторый объект вне компонента и записать FixedHeader в его свойство, если вам действительно нужно увидеть значение внутри обратного вызова события прокрутки

 const holder = {}
const Header = props => {
    const [FixedHeader, setFixedHeader] = useState('false');
    holder.value = FixedHeader

    const handleScroll = function () {
      console.log(window.scrollY)
      console.log(holder.value)
      if (window.scrollY >= 30) {
        setFixedHeader('true');
      } else {
        setFixedHeader('false');
      }
    }

    useEffect(() => {
        document.addEventListener("scroll", handleScroll)
        return () => window.removeEventListener('scroll', handleScroll);
    }, []);



    return (
  

но из-за того, что react не выполняет повторный запуск, иногда значение будет неправильным

Комментарии:

1. «Прямо сейчас я не вижу способа справиться с этим» Либо FixedHeader необходимо useEffect добавить в список зависимостей, а прослушиватели событий необходимо правильно удалить, либо можно использовать ссылку для получения «текущего» значения FixedHeader (при условии, что ссылка соответствующим образом обновляется).

2. Нет необходимости holder добавлять if FixedHeader в список зависимостей (теперь, когда вы все равно удаляете обработчик событий).

3. @FelixKling, да, вы правы, я изменил свой ответ, используя второй способ, но первый с зависимостями кажется более правильным

4. @FelixKling, но я просто сомневаюсь, что это действительно нужно для консоли. регистрируйте каждую прокрутку, я не вижу в этом смысла, поэтому может быть каждый раз, когда отправители компонентов добавляют прослушиватель событий и удаляют, это не очень хорошее решение… но в любом случае причина ясна

5. Конечно. Я предполагаю, что это просто для тестирования, чтобы увидеть, что происходит.

Ответ №2:

Причина, по которой «рендеринг» отображается дважды, заключается в том, что вы используете разные условия.

Для компонента класса, который вы используете:

 if (window.scrollY >= 25 amp;amp; !this.state.fixed) {
    // ...
} else if (window.scrollY < 25 amp;amp; this.state.fixed) {
    // ...
}
  

В то время как функциональный компонент использует:

 if (window.scrollY >= 30) {
    // ...
} else {
    // ...
}
  

Чтобы исправить эту проблему, вам нужно добавить проверку текущего состояния.

Однако, как вы уже заметили, проверка FixedHeader значения всегда будет приводить к одному и тому же значению (оно не обновляется). Итак, сначала нам нужно решить эту проблему.

Проблема в том, что setFixedHeader не обновляется FixedHeader в текущем контексте. Он сообщает React о повторном рендеринге, используя переданное значение как новое FixedHeader при следующем Header вызове, но FixedHeader в текущем контексте оно никогда не изменяется.

useEffect позволяет возвращать функцию, которая обрабатывает очистку. Эта функция запускается, если компонент отключается или перед следующим вызовом useEffect (когда список зависимостей изменился). Добавление FixedHeader в список зависимостей приведет к удалению предыдущего обработчика событий прокрутки (с использованием возвращаемой функции очистки) и добавлению нового обработчика событий прокрутки с использованием нового FixedHeader значения при изменении FixedHeader значения.

 const {useEffect, useState} = React;

const Header = props => {
    console.log("rendering");
    const [fixed, setFixed] = useState(false);

    useEffect(() => {
        const handleScroll = () => {
            console.log(window.scrollY);
            console.log(fixed);
            
            if (window.scrollY >= 30 amp;amp; !fixed) {
                setFixed(true);
            } else if (window.scrollY < 30 amp;amp; fixed) {
                setFixed(false);
            }
        };
        
        document.addEventListener("scroll", handleScroll);
        return () => document.removeEventListener("scroll", handleScroll);
    }, [fixed]);

    return null;
}

ReactDOM.render(<Header />, document.querySelector("#header-container"));  
 body { height: 1000px; }  
 <script src="https://unpkg.com/react@16/umd/react.production.min.js"></script>
<script src="https://unpkg.com/react-dom@16/umd/react-dom.production.min.js"></script>
<div id="header-container"></div>  

Комментарии:

1. Как сказал @FelixKling: «Каждый раз, когда компонент отображает новую переменную FixedHeader, создается». итак, я хочу знать, должен ли я придерживаться классов или изменить свой код на перехватчики react. (если критерием является производительность).

2. @anoop Да, каждый раз, когда компонент отображает, создаются новые переменные, но срок их службы также короче. Для простой логики функциональные компоненты часто выглядят чище. Я бы не стал слишком беспокоиться о производительности, пока это не станет проблемой. Предварительная оптимизация иногда может привести к тому, что вам будет сложнее понять код, что, в свою очередь, увеличивает время разработки.