Привет, я новичок в react/js, и я пытаюсь отсортировать некоторые данные, которые я извлекаю из API, используя Apollo, а затем отображаю данные в сетке. Когда я пытаюсь использовать функцию sort(), я получаю сообщение об ошибке в консоли «TypeError: Попытка изменить настраиваемый атрибут ненастраиваемого свойства». Может ли кто-нибудь помочь объяснить, что я делаю неправильно? Большое спасибо
Это код, который я пробовал. Работает без метода data.ammo.sort.
Я ожидал, что данные будут отображаться в порядке, отсортированном по повреждению
import { useQuery, gql } from '@apollo/client';
import AmmoBox from "./components/Ammo"
import {Grid} from "@chakra-ui/react"
export const GET_AMMO = gql
`{
ammo{
item {
id
name
shortName
}
damage
penetrationPower
caliber
}
}`
function App() {
const { loading, error, data } = useQuery(GET_AMMO);
if (loading) return 'Loading';
if (error) return 'Error';
console.info(data.ammo);
//sort data here before mapping to AmmoBox component*
data.ammo.sort((a, b) => a.damage - b.damage);
return (
<Grid templateColumns='repeat(5, 1fr)' gap = {6}>
{data.ammo
.map((ammos) => (
<AmmoBox name = {ammos.item.name} caliber = {ammos.caliber} penetration = {ammos.penetrationPower} damage = {ammos.damage}/>))}
</Grid>
);
}
export default App;



![Безумие обратных вызовов в javascript [JS]](https://i.imgur.com/WsjO6zJb.png)


Также можно использовать useMemo для уменьшения результатов рендеринга и кеша
function App() {
const { loading, error, data } = useQuery(GET_AMMO);
if (loading) return 'Loading';
if (error) return 'Error';
console.info(data.ammo);
const sortedData = useMemo(() => {
const copied = [...data?.ammo ?? [] ]
return copied.sort((a, b) => a.damage - b.damage)
}, [])
return (
<Grid templateColumns='repeat(5, 1fr)' gap = {6}>
{sortedData
.map((ammos) => (
<AmmoBox name = {ammos.item.name} caliber = {ammos.caliber} penetration = {ammos.penetrationPower} damage = {ammos.damage}/>))}
</Grid>
);
}
Надеюсь, поможет
Поскольку ошибка говорит, что вы не можете изменить data.ammo, распространите данные на новый (неглубоко скопированный) массив sortedArray и примените метод .sort() к этому новому массиву.
Проверьте код ниже:
function App() {
const { loading, error, data } = useQuery(GET_AMMO);
if (loading) return 'Loading';
if (error) return 'Error';
console.info(data.ammo);
// Spread ammo data to a new shallow-copied array and use sort() function on the new array
const sortedArray = [...data.ammo].sort((a, b) => a.damage - b.damage);
return (
<Grid templateColumns='repeat(5, 1fr)' gap = {6}>
{sortedArray
.map((ammos) => (
<AmmoBox name = {ammos.item.name} caliber = {ammos.caliber} penetration = {ammos.penetrationPower} damage = {ammos.damage}/>))}
</Grid>
);
}
Документы Mozilla - Array.prototype.sort() :
Метод sort() возвращает ссылку на исходный массив, поэтому изменение возвращаемого массива также приведет к изменению исходного массива.
Если вы хотите, чтобы sort() не изменяла исходный массив, а возвращала неглубоко скопированный массив, как это делают другие методы массива (например, map()), вы можете сделать поверхностную копию перед вызовом sort(), используя расширение синтаксис или Array.from().
Спасибо! В какой-то момент я попытался скопировать отсортированные результаты в новую переменную, но забыл написать data.ammo как [...data.ammo]. Очень признателен
Спасибо! Мне нужно немного прочитать об использовании Memo