Наблюдаю странное поведение реакта. У меня есть 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