reactjs - React: useState filtreleme dizisi durumunu güncellemiyor
Düzenle:
Hatalarım, useEffect'e ikinci parametre olarak bir dizi geçirdiğim için meydana geldi. Dizinin içindeki değerler aynı kalsa da, referans sürekli değişiyordu, bu nedenle useEffect sürekli çağrılıyor ve onay kutusu değerlerimi sıfırlıyordu. O dizi, bir useState çağrısıyla oluşturulmuştu. useState'i useReducer ile değiştirdim (reducer, nesne gerçekten değiştiğinde yalnızca nesne referansını değiştirir) ve bileşen ağacının daha üstünde eksik bazı bağımlılıkları güncelledim.
Orijinal soru:
Fonksiyonel bir bileşende bir durumu güncellemekte zorlanıyorum.
Sorunum bu soruya biraz benziyor: React SetState render çağırmıyor
Ben zaten state nesnemin kopyasını (array.filter kullanarak) alıyorum, referans vermek yerine; ama state’im yine de güncellenmiyor.
Sorunu izleyebilmek için, sorunu minimal bir örnekte yeniden yaratmayı denedim:
jsfiddle
Ama benim minimal örneğimde her şey beklendiği gibi çalışıyor. Hatanın tekrarını üretemiyorum.
İşte durumun güncellenmediği örneğim:
configCheckboxGroup.tsx:
import classNames from "classnames";
import React, { useState, useEffect } from "react";
import { Component } from "../../model";
import CheckboxPanel from "./panels/checkboxPanel";
interface configCheckboxGroupProps {
className?: string;
choices: Array<Component>;
selected: Array<string>;
addToCart: (items: Array<Component>) => void;
}
const ConfigCheckboxGroup: React.SFC<configCheckboxGroupProps> = ({
className,
choices,
selected,
addToCart,
}) => {
const [ selectedComp, setSelectedComp ] = useState<Array<string>>(selected);
// device loads later, selected has to be updated
useEffect(() => {
setSelectedComp(selected);
}, [selected]);
const handleOnChange = (ev: React.FormEvent, id: string) => {
console.debug(id);
console.debug(selectedComp.filter(el => el !== id));
if (selectedComp.includes(id)) {
// was already checked || this line is not working!
setSelectedComp(selectedComp.filter(el => el !== id));
} else {
// was not checked
setSelectedComp([...(selectedComp), id]);
}
const selected = choices.filter(el => selectedComp.includes(el.reference._id));
addToCart(selected);
};
return (
<div className={classNames("panellist", className)}>
{
choices.map(el => {
return (
<CheckboxPanel
image={ el.reference.picture ? el.reference.picture : undefined }
name={ el.reference.name }
id={ el.reference._id }
price={ el.reference.price ? el.reference.price :
el.price ? el.price : 0 }
key={ el._id }
checked={ selectedComp.includes(el.reference._id) }
onChange={ handleOnChange }
/>
)
})
}
<span>
{ selectedComp }
</span>
</div>
)
}
export default ConfigCheckboxGroup;
Ve checkboxPanel.tsx:
import classNames from "classnames";
import React from "react";
import "./checkboxPanel.scss";
import noImage from "../../../resources/images/errors/no-image.svg";
interface PanelProps {
className?: string;
image?: string;
name: string;
id: string;
price: number;
checked: boolean;
onChange: (ev: React.FormEvent, id: string) => void;
}
const CheckboxPanel: React.SFC<PanelProps> = ({
className,
image,
name,
id,
price,
checked,
onChange,
}) => {
const getImage = () => {
if (image) {
return image;
} else {
return noImage;
}
}
return (
<div className={classNames("panel", "checkbox-panel", className)}>
<div className="top">
<div className="image">
<img alt="Product" src={getImage()} />
</div>
<div className="name">
{name}
</div>
</div>
<div className="bottom">
<div className="category">
{ Number(price).toFixed(2) } €
</div>
<div>
<input type="checkbox"
checked={ checked }
onChange={ (e) => onChange(e, id) }
/>
</div>
</div>
</div>
)
};
export default CheckboxPanel;
Örnekler arasındaki tek fark, ikinci örnekte handle fonksiyonunu bir çocuk bileşen içinde çağırmamdır. Ama diğer durumlarda da aynı şeyi yapıyorum: Her şeyin sorunsuz çalıştığı, checkbox yerine radio butonları olan çok benzer bir Component configRadioGroup var.
Diziyi manuel olarak filtreleyerek ve birçok farklı şey deneyerek oynamayı denedim, ama hiçbir şey işe yaramıyor gibi görünüyordu. Bu yüzden, son bir deneme olarak buradan soruyorum (her ne kadar bu sorunun çok spesifik olması nedeniyle iyi bir soru olmadığını bilsem de).
Cevap #1
Prop selected'i değiştirmek, selectedComp'i sıfırlayacaktır; useEffect'inize bir console log koyarsanız, bunun her seferinde sıfırlandığını görebilirsiniz.
Seçilmişin nereden geldiğini (redux?) ve nasıl ayarlandığını (addToCart?) bulmanız gerekiyor.
Kirli bir çözüm, sadece bileşen monte edildiğinde selectedComp değerini ayarlamak olabilir, bu kirli bir yöntemdir ve react-hooks/exhaustive-deps lint'in tetiklenmesine neden olacak/olmalıdır:
useEffect(() => {
setSelectedComp(selected);
}, []);
Ama selected ile neyin yanlış gittiğini tespit etmek daha iyi, eğer redux'tan geliyorsa belki sadece selected kullan ve selectedComp'yi unut, çünkü o sadece bir kopya.
