componentWillUnmount works after switching to another page

260 Views Asked by At

I have two pages and two components LibraryPageFilters.tsx (url: /courses) and UserVideoCreatePage.tsx (url: /ugc/courses/${course.id}). In component LibraryPageFilters.tsx

useEffect(() => {
    console.log(course.id)
    if (course.id) {
      console.log(544)
      dispatch(push(`/ugc/courses/${course.id}`));
    }
  }, [course]);

i have a check that if course.id present in the store, then we make a redirect. In component UserVideoCreatePage.tsx

  useEffect(() => {
    return () => {
      console.log(333344444)
      dispatch(courseDelete());
    };
  }, []);

i am deleting a course from the store when componentUnmount.

enter image description here

why does unmount happen after a redirect? as a result, I am redirected back. Because the course is not removed from the store at the moment of unmount, and the check (if (course.id)) shows that the course is in the store and a redirect occurs back (dispatch(push(/ugc/courses/${course.id})))

UserVideoCreatePage.tsx

import React, { useEffect, useRef, useState } from 'react';
import { shallowEqual, useDispatch, useSelector } from 'react-redux';
import { useParams } from 'react-router';
import { Link } from 'react-router-dom';

import { Container } from 'Core/components/Container/Container';
import { Svg } from 'Core/components/Svg';
import { Button } from 'Core/Molecules/Button';
import { Select } from 'Core/Molecules/Select';

import {
  agreementCourse, categoriesSelector,
  courseDelete,
  courseEditorCourseSelector,
  courseUpdateApi, getCategories,
  getCourse,
  updateCourseApi,
} from 'Learnings/store/courseEdit';
import { CourseComments } from 'Learnings/screens/CoursePlayPage/CourseBottom/CourseComments/CourseComments';

import { AddItem } from './AddItem';
import s from 'Admin/Pages/Course/Description/index.scss';
import './UserVideoCreatePage.scss';

export const UserVideoCreatePage: React.FC = () => {
  const dispatch = useDispatch();
  const { id: idCourse } = useParams();
  const course = useSelector(courseEditorCourseSelector, shallowEqual);
  const categories = useSelector(categoriesSelector, shallowEqual);
  const [value, valueSet] = useState({ name: '', description: '', categories: [], lectures: [], materials: [] });
  const [tab, tabSet] = useState('program');
  const inputFileRef = useRef<HTMLInputElement>(null);
  const img = course.gallery_items && course.gallery_items[0];
  console.log(categories);
  const handleBtnClick = () => {
    if (inputFileRef && inputFileRef.current) {
      inputFileRef.current.click();
    }
  };

  useEffect(() => {
    dispatch(getCourse(idCourse));
    dispatch(getCategories());
  }, [idCourse]);

  useEffect(() => {
    valueSet({
      name: course.name,
      description: course.description,
      categories: course.categories && course.categories[0] && course.categories[0].id,
      lectures: course.lectures,
      materials: course.materials,
    });
  }, [course]);

  useEffect(() => {
    return () => {
      console.log(333344444)
      dispatch(courseDelete());
    };
  }, []);

  return (
    <Container className="createCourse">
      <Link to="/" className="gallery__back">
        <Svg name="arrow_back" width={26} height={20} className="gallery__svg"/>
        <span>Назад</span>
      </Link>

      <div className="createCourse__twoColumn">
        <div className="createCourse__twoColumn-left">
          <div className="inputBlock">
            <label className="inputBlock__label" htmlFor="video">
              Название видео-курса
            </label>
            <input
              id="video"
              type="text"
              placeholder="Введите название вашего видео"
              className="inputBlock__input"
              value={value.name || ''}
              onChange={e =>
                valueSet({
                  ...value,
                  name: e.target.value,
                })
              }
              onBlur={e => {
                if (e.target.value && course.name !== e.target.value) {
                  dispatch(updateCourseApi(idCourse, { name: e.target.value }));
                }
              }}
            />
          </div>
          <div className="inputBlock">
            <label className="inputBlock__label" htmlFor="opisanie">
              Описание видео-курса
            </label>
            <textarea
              id="opisanie"
              placeholder="Введите краткое описание вашего видео"
              className="inputBlock__input"
              value={value.description || ''}
              onChange={e =>
                valueSet({
                  ...value,
                  description: e.target.value,
                })
              }
              onBlur={e => {
                if (e.target.value && course.description !== e.target.value) {
                  dispatch(updateCourseApi(idCourse, { description: e.target.value }));
                }
              }}
            />
          </div>

          <Select
            title="Категории видео-курса"
            placeholder="Категории видео-курса"
            value={value.categories}
            options={categories.map(category => ({ value: category.id, label: category.name }))}
            onChange={val => {
              valueSet({
                ...value,
                categories: val,
              });

              dispatch(
                updateCourseApi(idCourse, {
                  category_ids: val,
                  courses_curators: {
                    '': {
                      user_id: val,
                    },
                  },
                }),
              );
            }}
            search
          />
        </div>

        <div className="createCourse__twoColumn-right">
          <div className="loadVideo">
            <div className="loadVideo__field">
              <div className="loadVideo__field--block">
                {!img && (
                  <>
                    <Svg className="loadVideo__field--block-icon" name="icn-load" width={104} height={69}/>
                    <p className="loadVideo__field--block-text">Загрузите обложку к видео</p>
                  </>
                )}
                {img && <img src={img && img.image_url} alt=""/>}
              </div>
            </div>
            <div className="loadVideo__under">
              <div className="loadVideo__under--left">
                <div className="loadVideo__under--text">
                  <span className="loadVideo__under--text-grey">*Рекомендуемый формат</span>
                  <span className="loadVideo__under--text-bold"> 356х100</span>
                </div>
                <div className="loadVideo__under--text">
                  <span className="loadVideo__under--text-grey">*Вес не должен превышать</span>
                  <span className="loadVideo__under--text-bold"> 10 Мб</span>
                </div>
              </div>
              <div className="loadVideo__under--right">
                <input
                  onChange={val => {
                    if (val.target.files[0]) {
                      if (img) {
                        dispatch(
                          updateCourseApi(idCourse, {
                            gallery_items: {
                              '': {
                                image: val.target.files[0],
                                id: img.id,
                              },
                            },
                          }),
                        );
                      } else {
                        dispatch(
                          updateCourseApi(idCourse, {
                            gallery_items: {
                              '': {
                                image: val.target.files[0],
                              },
                            },
                          }),
                        );
                      }
                    }
                  }}
                  type="file"
                  ref={inputFileRef}
                  className="Library__btn"
                />
                <Button
                  onClick={() => {
                    handleBtnClick();
                  }}
                >
                  Библиотека обложек
                </Button>
              </div>
            </div>
          </div>
        </div>
      </div>

      <div className={`block-switcher block-switcher--courseCreate`}>
        <div
          className={`block-switcher__item ${tab === 'program' && 'block-switcher__item_active'}`}
          onClick={() => tabSet('program')}
        >
          Программы
        </div>
        <div
          className={`block-switcher__item ${tab === 'comments' && 'block-switcher__item_active'}`}
          onClick={() => tabSet('comments')}
        >
          Комментарии эксперта
        </div>
      </div>

      {tab === 'program' && (
        <>
          <AddItem
            accept="video/mp4,video/x-m4v,video/*"
            fieldName="name"
            addType="lecture_type"
            title="Видео-курсы"
            addBtn="Добавить видео"
            type="lectures"
            file="video"
            lecturesArg={course.lectures}
            value={value}
            onChangeInput={lecturesNew => {
              valueSet({
                ...value,
                lectures: lecturesNew,
              });
            }}
            onVideoUpdate={(params: any) => {
              dispatch(updateCourseApi(idCourse, params));
            }}
            posMove={(lectures: any) => {
              dispatch(courseUpdateApi({ id: idCourse, lectures: lectures }, true));
            }}
          />
          <AddItem
            accept=""
            fieldName="title"
            addType="material_type"
            title="Материалы к видео-курсам"
            addBtn="Добавить файл"
            type="materials"
            file="document"
            lecturesArg={course.materials}
            value={value}
            onChangeInput={lecturesNew => {
              valueSet({
                ...value,
                materials: lecturesNew,
              });
            }}
            onVideoUpdate={(params: any) => {
              dispatch(updateCourseApi(idCourse, params));
            }}
            posMove={(lectures: any) => {
              dispatch(courseUpdateApi({ id: idCourse, materials: lectures }, true));
            }}
          />
        </>
      )}

      {tab === 'comments' && <CourseComments title="Обсуждение"/>}

      <Button
        className={`${s.button} agreement__btn`}
        size="big"
        onClick={() =>
          dispatch(
            agreementCourse(idCourse, {
              visibility_all_users: true,
            }),
          )
        }
      >
        Отправить на согласование
      </Button>
    </Container>
  );
};

LibraryPageFilters.tsx

import React, { useEffect, useState } from 'react';
import { useDispatch, useSelector, shallowEqual } from 'react-redux';
import { push } from 'connected-react-router';

import { getSettingsGlobalSelector } from 'Core/store/settings';
import { Svg } from 'Core/components/Svg';
import { NavBar } from 'Core/Organisms/NavBar';
import { Button } from 'Core/Molecules/Button';
import { CategoriesFilter } from 'Core/Organisms/Filters/components/CategoriesFilter';

import { courseDelete, courseEditorCourseSelector, createNewCourse } from 'Learnings/store/courseEdit';

import { FILTERS, LINKS } from '../../libraryPageConstants';
import { setLibraryPageQuery } from '../../actions/libraryPageActions';
import { getLibraryPageQuerySelector } from '../../libraryPageSelectors';

import s from './index.scss';
import { languageTranslateSelector } from 'Core/store/language';
import { LanguageType } from 'Core/models/LanguageSchema';
import { Status, Tabs } from 'Core/components/Tabs/Tabs';

const statuses: Array<Status> = [
  {
    key: 'Filter/all',
    link: '/courses' || '/courses',
    type: 'all' || '',
  },
  {
    key: 'Filter/online',
    link: '/courses/online',
    type: 'online',
  },
  {
    key: 'Filter/offline',
    link: '/courses/offline',
    type: 'offline',
  },
  {
    key: 'Filter/complete',
    link: '/courses/complete',
    type: 'complete',
  },
];

export const LibraryPageFilters = () => {
  const dispatch = useDispatch();
  const [searchTerm, setSearchTerm] = useState('');
  const [isBtnDisabled, setIsBtnDisabled] = useState(false);
  const course = useSelector(courseEditorCourseSelector, shallowEqual);

  const global = useSelector(getSettingsGlobalSelector);
  const query = useSelector(getLibraryPageQuerySelector, shallowEqual);
  const courseCreateButtonText = useSelector(
    languageTranslateSelector('CoursePage/courseCreateButton'),
  ) as LanguageType;
  const { category_id: categoryID } = query;
console.log(course)
  useEffect(() => {
    console.log(course.id)
    if (course.id) {
      console.log(544)
      dispatch(push(`/ugc/courses/${course.id}`));
    }
  }, [course]);

  useEffect(() => {
    return () => {
      setIsBtnDisabled(false);
      dispatch(courseDelete());
    };
  }, []);

  const onFilter = (values: any) => {
    return false;
  };

  const handleActiveCategory = (id: number) => {
    const categoryParam = {
      ...query,
      offset: 0,
      category_id: id,
    };

    if (id === categoryID) {
      delete categoryParam.category_id;
    }

    dispatch(setLibraryPageQuery(categoryParam));
  };

  const handleSearch = () => {
    dispatch(setLibraryPageQuery({ query: searchTerm }));
  };

  return (
    <React.Fragment>
      <div className={s.filters}>
        {global.coursesPage?.filters.length ? (
          <NavBar
            className={s.navBar}
            links={global.coursesPage.filtersLinks.map(linkType => LINKS[linkType])}
            filters={global.coursesPage.filters.map(filterType => FILTERS[filterType])}
            onFilter={onFilter}
            postfix={
              global.coursesPage.courseCreateButton && global.coursesPage.courseCreateButton.enable ? (
                <Button
                  className="coursePageCreateButton"
                  onClick={() => {
                    dispatch(createNewCourse());
                    setIsBtnDisabled(true);
                  }}
                  disabled={isBtnDisabled}
                >
                  {courseCreateButtonText['CoursePage/courseCreateButton']}
                </Button>
              ) : null
            }
          />
        ) : (
          <div className="track-page__header" data-tut="track-header">
            <Tabs statuses={statuses} />
            <div className={s.filtersSearch}>
              <Svg className={s.filtersSearchIcon} name="search_alternative" width={18} height={18} />
              <input
                type="text"
                placeholder="Поиск"
                className={s.filtersSearchInput}
                value={searchTerm}
                onChange={event => setSearchTerm(event.target.value)}
              />
              <button type="button" className={s.filtersButton} onClick={handleSearch}>
                Найти
              </button>
            </div>
          </div>
        )}
      </div>

      <CategoriesFilter onChange={handleActiveCategory} selectedID={categoryID} />
    </React.Fragment>
  );
};
1

There are 1 best solutions below

1
On

Although react suggests to use Functional Component, try Class Component, I faced similar issues, this was resolved easily in Class Component :

componentDidMount();
componentDidUpdate(prevProps, prevState, snapshot);

These two will solve your problem. Ask me if anything you need.