#javascript #arrays #reactjs #react-props
Вопрос:
Не знаю, как это исправить. Мы получаем массив объектов из нашего API и используем его для создания данных в представлении. В то же время в дочернем компоненте (фильтры) Я хочу сопоставить одно из полей в данных, чтобы создать свои категории фильтров. Фильтр вызовет новые данные из API с параметром, и эти данные будут возвращены и обновят реквизиты (я думаю, что это проблема, так как это перенаправляет дочерний компонент, используя отфильтрованные данные, чтобы снова задать категории).
Я думал, что помещение массива в useEffect остановит его обновление.
Вот текущий tsx в моем компоненте фильтра:
const ExclusiveOffersFilters = (props: ExclusiveOffersFiltersProps): JSX.Element => {
const newFilters = JSON.parse(JSON.stringify(props.options)); // copy the object from props
let filterOffers;
useEffect(() => {
filterOffers = newFilters.map((item: any) => {
return { value: item.offerType, display: item.offerType };
});
console.log('filterOffers: ', filterOffers); // succesfully logs the filtered items.
}, []);
return (
<tr>
<th>
<Filter
options={filterOffers} // here filterOffers is undefined
alignRight={props.alignRight}
handleClick={props.handleFilterChange}
multiSelect={props.multiSelect}
selectedItems={props.selectedItems}
/>
</th>
</tr>
);
};
Я также попробовал const newFilters = [...props.options];
и newFilters = props.options.slice(0)
, но это та же проблема (казалось, разумнее было использовать JSON-анализ/stringify).
В моем родительском компоненте я называю ребенка так:
<ExclusiveOffersFilters handleFilterChange={props.handleFilterChange} options={props.options} />
Если я удалю useEffect
функцию и просто обновлю фильтры, она будет работать, однако после выбора одного фильтра приложение обновит вызов api, получит обратно только отфильтрованные данные, и поэтому в фильтрах задана только одна категория. Что мне нужно предотвратить.
Мне нужен способ получить исходные категории и заморозить их обновление.
Редактировать
Вот наши примерные данные:
const data = [
{
offerId: 1,
partnerName: "Another offer 4",
imageUrl:
"https://www.auctsjpg-w263-h98-99382466814e33da0cfa3d5d2afd921c.jpg",
description:
"Save up to 10% on something. <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</p> <p>Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p> <p>Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.</p>",
header: "Save up to 10%",
enabled: true,
deleted: false,
offerType: "Motoring"
},
{
offerId: 0,
partnerName: "Amazing offer 4",
imageUrl: "https://www.cGen",
description:
"Save up to 20% off* your business insurance thanks to our partnership with<BR/> Churchill Expert. Simply visit the Churchill Expert web page and choose the<BR/> insurance product to suit your business.<BR/> Churchill Expert will automatically apply the discount to your premium for the<BR/>duration of your policy. <BR/><BR/>*Minimum premiums apply. Discount applies to NIG policies arranged by Churchill Expert <BR/>and underwritten by U K Insurance Limited.<BR/> Professional Indemnity excluded.",
header: "Save up to 20% off",
enabled: true,
deleted: false,
offerType: "Insurance"
},
{
offerId: 190,
partnerName: "Amazing offer 4",
imageUrl: "https://www.ch.Code=ExpertGen",
description:
"Save up to 20% off* your business insurance thanks to our partnership with<BR/> Churchill Expert. Simply visit the Churchill Expert web page and choose the<BR/> insurance product to suit your business.<BR/> Churchill Expert will automatically apply the discount to your premium for the<BR/>duration of your policy. <BR/><BR/>*Minimum premiums apply. Discount applies to NIG policies arranged by Churchill Expert <BR/>and underwritten by U K Insurance Limited.<BR/> Professional Indemnity excluded.",
header: "Save up to 20% off",
enabled: true,
deleted: true,
offerType: "Insurance"
}
];
export default data;
Если мы отфильтруем по типу предложения = Автомобильное движение, то мы снова вызовем наш api с автомобильным движением в качестве фильтра, это вернет только 1 запись из приведенных выше данных, но теперь наш фильтр обновляется и показывает только 1 категорию фильтра автомобильного движения.
Смотрите прилагаемые примеры из приложения.
Я сбросил большую часть файлов сюда: https://codesandbox.io/s/charming-sinoussi-l2iwh?file=/data.js:0-2061 с образцами данных. Я не знаю, насколько это полезно, трудно привести рабочий пример, когда существует так много зависимостей.
Родительский index.tsx обрабатывает все вызовы api ajax и передает данные в реквизит. Файл ExclusiveOffersFilters.tsx получает это и обновляется, и это та часть, которую я хочу остановить. Как отмечает @Adam в комментариях, мы пытаемся это исправить, но я думаю, что на самом деле с родителем все в порядке, проблема в ребенке.
Мы действительно хотим применить эту логику в другом месте приложения, поэтому производительность будет хорошей. Мне интересно, нужно ли мне просто не использовать props.options и использовать для этого другую опору?
Комментарии:
1. Похоже, вы пытаетесь исправить проблему в своем дочернем компоненте, применив взлом в родительском компоненте (две ошибки не делают правильного). Опубликуйте код для дочернего компонента, и у меня такое чувство, что сразу станет очевидно, в чем проблема.
2. @Adam Я обновил свой вопрос, добавив ссылку на большинство файлов, примеры данных и скриншоты проблемы.
Ответ №1:
useEffect
выполняет асинхронно, поэтомуfilterOffers
может быть неопределенным в момент рендеринга.- Если вы хотите создать значение на основе какого-либо другого значения и хотите оптимизировать его, используйте
useMemo
hook. - Если вы хотите сохранить значение между повторными визуализациями компонента, используйте
useRef
крюк.const newFilters = useRef(JSON.parse(JSON.stringify(props.options))); // copy the object from props const filterOffers = useMemo(() => { filterOffers = newFilters.current.map((item: any) => { return { value: item.offerType, display: item.offerType }; }); console.log('filterOffers: ', filterOffers); // succesfully logs the filtered items. }, [newFilters]);
Комментарии:
1. Почему вы используете
useRef
? Вы добавляетеnewFilters
в качестве зависимостиuseMemo
?newFilters
является рефератом и никогда не изменится.2. Возможно, я неправильно понял вопрос, но идея заключалась в том, чтобы сохранить их между повторными рендерами.
3. Насколько я понял, OP хочет сохранить исходные фильтры между повторными визуализациями, поэтому я использую
useRef
4. Эй, спасибо за это, я никак не могу заставить его работать. Но вы сделали filterOffers константой, а затем снова вызываете ее внутри функции useMemo. Я обновил свой вопрос ссылкой на ресурсы, примеры данных и скриншоты. Я думаю, что функция должна быть
const filterOffers = useMemo(() => { return filterOffers = newFilters.current.map((item: any) => { return { value: item.offerType, display: item.offerType }; }); console.log('filterOffers: ', filterOffers); // succesfully logs the filtered items. }, [newFilters]);
5. @lharby извините, но в силу того , что этот ответ помещен
newFilters
в массив зависимостейuseMemo
, он ясно демонстрирует непоследовательность этого ответа. Это тебе не поможет.
Ответ №2:
Это все, что вам нужно. Если у вас возникнут проблемы с производительностью, используйте useMemo
. Если у вас не возникнет проблем с производительностью, ничего не предпринимайте
const ExclusiveOffersFilters = (props: ExclusiveOffersFiltersProps): JSX.Element => {
const filters = props.options.map((item) => ({
value: item.offerType,
display: item.offerType
}));
return (
<tr>
<th>
<Filter
options={filters}
alignRight={props.alignRight}
handleClick={props.handleFilterChange}
multiSelect={props.multiSelect}
selectedItems={props.selectedItems}
/>
</th>
</tr>
);
};
Пример с useMemo
const filters = useMemo(() => props.options.map(....),[props.options]);
Я не могу достаточно сильно напрягаться, чтобы держаться подальше, useMemo
если вы не абсолютно уверены, что вам это нужно.
Комментарии:
1. Спасибо, я попробую, но я подозреваю, что реквизит.параметры будут обновлены при повторном отправке.
2. @lharby Так и будет, но я перечитал ваш вопрос и две вещи-во — первых, вся информация о JSON.parse JSON.stringify-это чепуха, а во-вторых, вы пытаетесь исправить ошибку в своем нижнем компоненте, добавив взлом в этот компонент. Опубликуйте код для нижнего компонента, который, как вы говорите, продолжает обновляться, и исправьте ошибку там, где она есть на самом деле, вместо того, чтобы взламывать этот компонент.
3. Хорошо, я заберу это завтра и обновлю, большое вам спасибо за ваш вклад
4. @lharby — ваш кодовый код сейчас не работает, но я почти могу гарантировать, что проблема связана с вашим использованием
splice
иpush
Filter.tsx
использованием . Когда дело доходит до реакции, не изменяйте ничего, состояние, реквизит, ничего.