LoginSignup
1
0

More than 3 years have passed since last update.

Reactで削除したliタグをsetStateで消そうとしたら苦労した件

Last updated at Posted at 2019-12-23

やろうとしたこと

配列peopleに入ってる人たちをliで表示して、
削除ボタン押したら、フロントから消し去る
(ちなみに、サーバサイドはGraphQL。今回は特に関係ないので割愛)

peopleは、こんな感じで定義してあるよ。
const [people, setPeople] = useState<string[]>([]);

return (
  <>
    <ul>
     {people.map(person => (
           <li onClick={handleDelete}>{person}</li>
        )
     )}
    </ul>
  </>
);

かなり簡略化して書きました。まあ多少はね?
mapでpersonをリストで表示させる。
で、personをクリックするとhandleDeleteが呼ばれてその中でサーバサイドのデータが削除され
フロントからも消えるはず、はずだったw

peopleという配列はコンポーネントが描画されるときに
GraphQLのフックが起動して取得した配列を
setPeople(pickUpPeople)みたいな感じで突っ込んでいるのですが・・・
このフックは最初に描画した時、1度しか呼ばれない

つまり、サーバサイドではデータは消えているけど
フロント側は何も変化がないということになる。
(もちろん、F5で更新すれば消えている)

失敗例

「せや、デリートボタン押したときに
配列にフィルターかけてsetPeopleしなおせばええんや!」

具体的には、
setPeople(pickedUpPeople.filter(person => person !== デリートしたpersonのid))
要するに、peopleにデリートしたidに合致しないやつだけピックアップしてセットする。
という意味。

結果

「テストデータが2つ・・・1つを削除・・・を消えた!!」
「よし、もう一つも削除・・・!?・・・さっき消したやつ戻ってきた・・・」
「連打してみよ・・・交互に消したはずのデータがひょこひょこ出てくるンゴ^q^」

なぜかというと、
フックで取ってきたpickedUpPeople配列からはデータが消えているわけではないので
クリックされたやつ以外が表示されてしまう・・・
つまり、別なのを削除するとそれは消えるけど、前のやつがリバイブする
image.png

成功例

delete押されたidをステートで管理して、そこに足していけばええんや!
なので、さっきのコードをこんな感じにする。
* ...deletedListは配列の中身をバラして並べる、という意味です

const[deletedList, setDeletedList] = useState<string[]>([])
setPeople(
  pickedUpPeople.filter(
    person =>
      ![デリートしたpersonのID, ...deletedList].includes(person.id),
  ),
);
setDeletedList([デリートしたpersonのID, ...deletedList]);

こうすれば、一回消したidがどんどんListに追加されていくので
フックで取得した全体と消し去ったListのXORを取ることで
消されていない奴らだけ表示できた!

もっとお利口な方法があるんだろうけど、
元のコードを崩さずにやろうとしたらこうなりました(小並感)

まとめ

・Reactでliを扱う時は、filterをうまく使う
・弾くべきデータをリストとして、別のステートに保持しておくと便利

1
0
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0