@wb_by
Учусь

Как заставить перерендерить компонент?

Наблюдаю странное поведение реакта. У меня есть 3 по-сути одинаковые страницы - функциональные компоненты, но у них разные роуты и проп type. На этих страницах есть компонент TextField из material ui, value которого связано со стейтом redux. При переходе между этими страницами стейт сбрасывается и value у TextField становится пустой строкой. Но так как мы по сути при переходе на другую страницу просто меняем type, то компонент этот не ререндерит TextField. В итоге получаем в стейте redux пустую строку, а в TextField прошлое значение. Вопрос: как можно заставить React перерендерить этот TextField? Сейчас решение - просто для каждой этой страницы добавить в роутере прослойку из разных html компонентов, чтобы заставить перерендерить дерево, но выглядит это очень плохо.

p.s. Если что никаких мемоизаций не используется, по крайней мере у меня в коде.

Код компонента:
import { useCallback, useEffect, useState } from "react"

//ftl api
import { FTLStatusTag, useLayout } from "ftl-dashboards-ui-kit"
import { useListPage, FTLObjectUtils } from "ftl-dashboards-core"
//other
import {
  statusLabels,
  statusItems,
  listTitleToType,
  getExternalServices,
} from "./model"
import { Cell } from "react-table"

//types
import { ExternalService, ExternalServiceRequest } from "../../types/entities"
import { FTLListPage } from "ftl-dashboards-templates"

const columns = [
  {
    Header: "Наименование",
    accessor: "name",
    width: 500,
    disableSortBy: true,
  },
  {
    Header: "Активность",
    accessor: "activeStatus",
    width: 180,
    disableSortBy: true,
    Cell: (props: Cell) => {
      const value = props.value
      return (
        <FTLStatusTag
          status={value === "ACTIVE" ? "success" : "error"}
          style={{
            display: "inline-block",
          }}
        >
          {statusLabels[value]}
        </FTLStatusTag>
      )
    },
  },
  {
    Header: "Создан",
    width: 150,
    accessor: "createdAt",
    align: "right",
    reverse: true,
  },
  {
    Header: "",
    width: 80,
    accessor: "action",
    disableSortBy: true,
  },
]

export const ExternalServicesList = ({
  type = "ORDER_SYNC",
}: Pick<ExternalService, "type">) => {
  const baseUrl = `/${window.location.pathname.split("/")[1]}${
    type === "SMS" ? "/params" : ""
  }`
  const [data, setData] = useState<ExternalService<"GET">[]>([])

  const {
    pageCount,
    isFetching,
    query,
    history,
    sortName,
    sortDirection,
    limit,
    offset,
    filters,
    path,
    setFilters,
    setPageCount,
    setQuery,
    setIsFetching,
  } = useListPage()

  const fetchExternalServices = useCallback(
    async (request: ExternalServiceRequest) => {
      getExternalServices(request, {
        setIsFetching,
        setData,
        setPageCount,
        type,
      })
    },
    [type]
  )

  useEffect(() => {
    setData([])
    setPageCount(0)
  }, [type])

  useEffect(() => {
    fetchExternalServices({
      query: filters.query,
      activeStatus: filters.activeStatus?.value,
      sortName,
      sortDirection,
      limit,
      offset,
      type,
    })
  }, [filters, sortName, sortDirection, limit, offset, type])

  const page = useLayout({
    components: {
      Header: {
        title: listTitleToType[type],
        primaryButton: {
          label: "Новый сервис",
          onClick: () => history.push(`${baseUrl}/new`),
        },
      },
      Table: {
        data,
        columns,
        pageCount,
        isFetching,
        setIsFetching,
        actionsSize: 2,
        isSearching: Boolean(FTLObjectUtils.getNotEmptyFieldsCount(filters)),
        pageSize: limit,
        rowDisable: (row) => {
          if (row.original.activeStatus === "ARCHIVE") return true
          return false
        },
        onRowClick: (row) => {
          row.original.id && history.push(`${baseUrl}/${row.original.id}`)
        },
      },
    },
  })

  return (
    <FTLListPage
      headerComponent={page.Header}
      tableComponent={page.Table}
      searchProps={{
        value: query,
        onChange: (value) => {
          setQuery(value)
        },
        placeholder: "Наименование",
      }}
      filters={[
        {
          isSearchable: false,
          placeholder: "Активность",
          options: statusItems,
          onChange: (option) => {
            setFilters({ activeStatus: option })
          },
          value: filters.activeStatus,
        },
      ]}
    />
  )
}

export default ExternalServicesList
  • Вопрос задан
  • 138 просмотров
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы