Are you sure you want to delete the question?

If your question is resolved, you may close it.

Leaving a resolved question undeleted may help others!

We hope you find it useful!

特定の配列要素を削除した際、mapで出力がおかしい

解決したいこと

特定の番号の配列要素を削除した際、mapで出力される配列が何故か一番下の要素が削除された状態になる。
スクリーンショット 2021-09-05 11.48.24.png
スクリーンショット 2021-09-05 11.48.51.png

ReduxのStore情報は正しい順番で出力されている
スクリーンショット 2021-09-05 11.48.51のコピー.png

ブラウザを再読み込みすれば正しい順番で再出力されるが、リアルタイムで要素を削除できるようにしたい

該当するソースコード

LikeExist.tsx

import React, {useState} from 'react';

export const LikeExist = (props) => {
  const [like, setLike] = useState(props.like);
  const saveLike = (e) => {
    e.preventDefault();
    setLike(e.target.value);
  }
  return (
    <li className="item" key={props.index.toString()}><input className="text-input" type="text" value={like} onChange={saveLike} onBlur={() => props.editLike(like, props.index)}/><input className="submit" value="ー" type="submit" onClick={() => props.deleteLike(props.index)}/></li>
  )
}

likes.tsx

import React, {useState} from 'react';
import { LikeExist } from './LikeExist';

export default function Likes(props) {
  const [like, setLike] = useState("");

  const saveLike = (e) => {
    e.preventDefault();
    setLike(e.target.value);
  }

  let likeInput = null;
  if (typeof document !== 'undefined') {
    likeInput = document.getElementById('addLike') as HTMLInputElement;
  }
  const submitTxt = (e) => {
    if(like !== "" && like !== null) {
      e.preventDefault();
      props.addLike(like);
      likeInput.value = "";
      setLike("");
    }
  }
  return (
  <section className="likes list-sec">
    <h2 className="list-ttl">好き</h2>
    <ul className="list">
      {props.likes.map((like: string, index: number) => {
        return (
          <LikeExist like={like} index={index} editLike={props.editLike} deleteLike={props.deleteLike}/>
        )
      })}
      <li className="item">
        <input
          className="text-input"
          type="text"
          id="addLike"
          placeholder="ここに文字を入力してください"
          onBlur={saveLike}
        />
        <input className="submit" value="+" type="submit" onClick={submitTxt} />
      </li>
    </ul>
  </section>
  )
}

index.tsx

import React, {useState, useEffect} from 'react';
import {Profile, Likes, Dislikes} from '../../src/components/index';
import { db, FirebaseTimestamp } from '../../src/firebase';
import { useSelector, useDispatch } from 'react-redux';
import { getUserId, getUsername, getIsLogined, getLikes } from '../../src/reducks/users/selectors';
import { addLikesToStore, listenAuthState } from '../../src/reducks/users/operations';
import router from 'next/router';

export default function LoginedTop() {
  const selector = useSelector((state) => state);
  console.log(selector);
  const uid = getUserId(selector);
  const username = getUsername(selector);
  const isLogined = getIsLogined(selector);
  const likesFromStore = getLikes(selector);
  console.log("likesFromStore: " + likesFromStore);

  const dispatch = useDispatch();

  const [likes, setLikes] = useState([]);
  const [dislikes, setDislikes] = useState(["生玉ねぎ", "ゴキブリ", "怒られること", "ニセコイ", "The Crystal Ship"]);
  console.log(likes)
  console.log(likes.length)
  console.log(likesFromStore);
  console.log(likesFromStore.length);
  if(likesFromStore.length > 0 && likes.length === 0) {
    setLikes(likesFromStore);
  }

  useEffect(() => {
    if(!isLogined) {
      dispatch(listenAuthState());
    }
  });

  useEffect(() => {
    if(likes !== likesFromStore) {
      dispatch(addLikesToStore(likes));
    }
  }, [likes]);

  const addLike = (item: string) => {
    setLikes(prevLikes => {
      return [...prevLikes, item]
    });
  }

  const editLike = (item: string, index: number) => {
    let likesCopy = [...likes];
    likesCopy[index] = item;
    setLikes(likesCopy);
  }

  const deleteLike = (index: number) => {
    if(index !== null &&  index !== undefined) {
      let likesCopy = [...likes];
      likesCopy.splice(index, 1);
      setLikes(likesCopy);
    }
  }

  const addDislike = (item: string) => {
    setDislikes(prevDislikes => {
      return [...prevDislikes, item]
    });
  }
  const editDisLike = (item: string, index: number) => {
    dislikes[index] = item;
  }


  return (
    <>
      <Profile username={username} />
      <Likes likes={likes} addLike={addLike} editLike={editLike} deleteLike={deleteLike}/>
      <Dislikes dislikes={dislikes} addDislike={addDislike} editDislike={editDisLike}/>
    </>
  )
}

operations.ts

export const addLikesToStore = (likes) => {
  return async (dispatch, getState) => {
    dispatch(addLikesToStoreAction(likes));
    const state = getState();
    const uid = state.uid;
    if (uid !== "") {
      db.collection('users').doc(uid).update({
        likes: likes
      })
        .then(() => {
          console.log("AddLike Success!");
        })
        .catch((error) => {
          alert(`Error:${error}`);
        });
    }
  }
}
0

2Answer

Comments

  1. @takahiro1227

    Questioner

    回答ありがとうございます。
    key={props.like}に変えてみたのですが、うまくいきませんでした。spliceで配列を詰めると、mapで得られるindexの最後の1個が消えるということがよく理解できないのですが、その仕組みについてご教示いただけないでしょうか?

混乱させてしまい申し訳ありません。(mapの要素を読み間違えていました)
こちらでも環境を作ってみました。

keyにindexをつかっているのが問題なのではなく、map処理の

<LikeExist like={like} index={index} editLike={props.editLike} deleteLike={props.deleteLike}/>

にkeyが無いのが問題でした。
とりあえず、下記のようにすれば動きました。
(likeの文字列が重複しないことが条件ですが)

<LikeExist like={like} index={index} key={like} editLike={props.editLike} deleteLike={props.deleteLike}/>

indexの件は

["なんだよマジ","くっそー","あいうえお","かきくけこ"]

の時点では

<li key="0"><input value="なんだよマジ"></li>
<li key="1"><input value="くっそー"></li>
<li key="2"><input value="あいうえお"></li>
<li key="3"><input value="かきくけこ"></li>

なのですが、削除すると

["なんだよマジ","くっそー","かきくけこ"]

となって

<li key="0"><input value="なんだよマジ"></li>
<li key="1"><input value="くっそー"></li>
<li key="2"><input value="かきくけこ"></li>

となってほしいのですが、
key="0"key="2"には変化がなくkey="3"が消えたと判断されて最後が消されるんだと思います。

0Like

Comments

  1. @takahiro1227

    Questioner

    やっとできました・・。環境まで作って確認していただきありがとうございました。
    indexで最後が消える理由もわかりやすかったです。
    本当に助かりました!

Your answer might help someone💌