Рефакторинг компонента на основе класса в функциональный компонент - PullRequest
0 голосов
/ 18 апреля 2020

TL; DR: я пытаюсь реорганизовать свой компонент приложения на основе классов в функциональный компонент, и у меня возникают некоторые неожиданные результаты с использованием крюка useEffect.

Я довольно новичок в React и версии мое приложение для поиска фильмов с помощью OMDB API было основано на классах. Это работало хорошо, поэтому я хотел немного попрактиковаться в работе с хуками и контекстом, прежде чем углубляться в излишний.

В моем компоненте класса был следующий код:

componentDidMount = () => {
    window.onscroll = this.handleScroll;
  };

  handleScroll = () => {
    if (!this.state.movies.loading) {
      if (getScrollDownPercentage(window) > 0.8) {
        const nextPage = this.state.movies.page + 1;
        this.searchMovies(this.state.movies.searchValue, nextPage);
        this.setState({
          ...this.state,
          movies: {
            ...this.state.movies,
            page: nextPage,
          },
        });
      }
    }
  };

  searchMovies = (str, page = 1) => {
    const existingMovies =
      this.state.movies.data.length && this.state.movies.searchValue === str
        ? this.state.movies.data
        : [];
    this.setState({
      ...this.state,
      movies: {
        ...this.state.movies,
        loading: true,
      },
    });
    axios
      .get(`${process.env.REACT_APP_ENDPOINT}s=${str}&page=${page}`)
      .then((response) => {
        if (response.data.Response === "True") {
          this.setState({
            ...this.state,
            movies: {
              ...this.state.movies,
              loading: false,
              searchValue: str,
              data: [...existingMovies, ...response.data.Search],
            },
          });
        }
      });
  };

После рефакторинга У меня есть следующий код, который кажется менее чистым (поэтому противоположность того, что я надеялся достичь)

В тот момент, когда я достигаю конца страницы, я получаю безостановочный поток топора ios переключение вызовов между страницей 2 и 3

Если я не ошибаюсь, это не работает, потому что setState работает асинхронно и я получаю постоянные обновления на своей странице.

  useEffect(() => {
    window.onscroll = () => {
      handleScroll();
    };
    if (searchValue) {
      console.log(page);
      searchMovies(searchValue, page);
    }
    return () => {
      window.removeEventListener("scroll", handleScroll);
    };
  }, [searchValue, page]);

  const handleScroll = () => {
    if (!loading && searchValue) {
      if (getScrollDownPercentage(window) > 0.7) {
        setState({
          ...state,
          movies: {
            ...state.movies,
            page: page + 1,
          },
        });
      }
    }
  };

  const searchMovies = (str, page = 1) => {
    const existingMovies = data.length && prevSearchValue === str ? data : [];
    setState({
      ...state,
      movies: {
        ...state.movies,
        loading: true,
      },
    });
    axios
      .get(`${process.env.REACT_APP_ENDPOINT2}s=${str}&page=${page}`)
      .then((response) => {
        if (response.data.Response === "True") {
          setState({
            ...state,
            movies: {
              ...state.movies,
              loading: false,
              searchValue: str,
              data: [...existingMovies, ...response.data.Search],
            },
          });
        } else {
          setState({
            ...state,
            movies: {
              ...state.movies,
              loading: false,
              error: true,
            },
          });
        }
      });
  };

I надеюсь, что я включил все (и также не слишком много), чтобы прояснить мою проблему. Обращаю внимание на некоторых волшебников React.

Редактировать: еще немного указать указанную проблему и выделить ее жирным шрифтом

Ответы [ 2 ]

1 голос
/ 18 апреля 2020

Учитывая ваш ответ, я думаю, что вы хотели бы сделать несколько useEffects: один для searchMovies и один для настройки прокрутки.

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

useEffect(() => {
  if (searchValue) {
    console.log(page);
    searchMovies(searchValue, page);
  }
}, [searchValue, page])
0 голосов
/ 18 апреля 2020

Быстрое исправление будет использовать пустой массив в качестве второго аргумента, чтобы избежать бесконечного l oop

useEffect(() => {
    //your code
  },[]);
...