Переделать компонент класса в функциональный компонент hooks

#reactjs

#reactjs

Вопрос:

У меня есть компонент класса:

 import React, { Component, Fragment } from 'react';
import ReactPlayer from 'react-player';

import storage from '../../utils/localStorage';

const STORAGE_VIDEOS_DATA_KEY = 'VIDEOS_DATA';

class VideoItem extends Component  {
  constructor(props) {
    super(props);

    this.state = {
      playingStatus: false,
      videoId: 318298217,
    };
  }

  componentDidMount() {
    window.addEventListener(
      'beforeunload',
      this.saveStateToLocalStorage
    );
  }

  componentWillUnmount() {
    window.removeEventListener(
      'beforeunload',
      this.saveStateToLocalStorage
    );

    this.saveStateToLocalStorage();
  }

  handlePlayingStatus = () => {
    this.seekToPoint();

    this.setState({
      playingStatus: true,
    });
  }

  setVideoProgress = videoProgress => {
    this.setState({
      videoProgress: videoProgress.playedSeconds,
    });
  }

  onVideoPause = () => {
    this.saveStateToLocalStorage();

    this.setState({
      playingStatus: false,
    });
  }

  onVideoEnd = () => {
    console.log('backend call - video end status');
  }

  seekToPoint = () => {
    const { videoId } = this.state;

    const videosData = storage.hasKey(STORAGE_VIDEOS_DATA_KEY) amp;amp;
      JSON.parse(storage.getItem(STORAGE_VIDEOS_DATA_KEY));
    const toReturnVideoPoint = videosData[videoId] || 0;
    this.player.seekTo(Number(toReturnVideoPoint));
  }

  saveStateToLocalStorage = () => {
    const { videoProgress, videoId } = this.state;

    const videosPlayedDuration = {
      [videoId]: videoProgress,
    };

    storage.setItem(STORAGE_VIDEOS_DATA_KEY, JSON.stringify(videosPlayedDuration));
  };

  render() {
    const { playingStatus, videoId } = this.state;

    return (
      <Fragment>
        <ReactPlayer
          ref={player => { this.player = player; }}
          playing={playingStatus}
          url={`https://player.vimeo.com/video/${videoId}`}
          onPause={this.onVideoPause}
          onEnded={this.onVideoEnd}
          onProgress={this.setVideoProgress}
        />
        <button onClick={this.handlePlayingStatus}>GO BACK TO THE PREVIOUS POINT</button>
      </Fragment>
    );
  }
}

export default VideoItem;
  

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

Как я могу остановить слишком много повторных запусков логики componentDidMount в useEffect hook?

Ответ №1:

Передать пустой массив в качестве параметра, например:

 useEffect(() => {
  window.addEventListener(
    'beforeunload',
    saveStateToLocalStorage
  );

  return () => {
    window.removeEventListener(
      'beforeunload',
      saveStateToLocalStorage
    );
    saveStateToLocalStorage();
  };
}, []);
  

При использовании useEffect это похоже на использование componentDidMount , componentDidUpdate и componentWillUnmount в одном и том же хукле. Тело вашей функции — это то, что выполняется при монтировании вашего компонента и при каждом обновлении, которое он получает. Функция возврата — это то, что выполняется перед отключением вашего компонента.

Вы можете передать второй необязательный параметр, массив значений, чтобы указать React повторно запускать функцию только тогда, когда изменились некоторые переменные между рендерами. Когда вы передаете пустой массив, вы просто говорите React никогда не обновлять его вообще.

Проверьте документацию React Hooks, чтобы узнать больше об этом.