[react]usState()を使用して配列(feat.日記帳)を変更する


配列内のリスト内の項目を動的に変更する(条件付きレンダリング)

🎯コーディング順序の整理

  • DiaryItem.jsに変更ボタンを生成します.
  • 「修正」ボタンをクリックしてボタンを「修正解除」、「修正完了」ボタンに変更し、「修正完了」ボタンをクリックして再度修正し、「削除」ボタン(if関数とusStat関数を使用)に戻る
    つまり、作成機能が必要なボタンは「修正」、「修正解除」、「修正完了」です.
  • 修正ボタンをクリックし、日記本文にマウスカーソルを置き、書いた内容をtextareaに表示する機能
  • 「修正」ボタンをクリックし、「修正解除」ボタンをクリックすると、作成中のコンテンツが表示される機能
  • 修正完了ボタンをクリックし、修正中の内容を新しい内容に更新する必要があります.
  • ここで,Reactの特性により,データは上から下へ一方向に流れ,イベントは下から上へ逆方向に流れた.
    修正完了ボタンを考えると、新しいイベントが発生し、修正完了ボタン付きのDiaryItemが発生します.jsコンポーネントから親コンポーネントへApp.イベントはjsで渡す必要があるため、Appコンポーネントで変更すると関数が作成され、Appに変換されます.jsのサブコンポーネントDiaryList.jsアイテムにDiaryListを付けるjsのサブアセンブリDiaryItem.js道具をあげればいいです.(最終呼び出し関数の場所はDiaryItem.js)

    💡使用する概念


    useState(), useRef(), props, onClick, !, onChange,3項演算子
    もう一度復習しましょう.私たちはよく概念を破らなければなりません.🤩

    📖例


    1. App.js

    import { useRef, useState } from "react";
    import "./App.css";
    import DiaryEditor from "./DiaryEditor";
    import DiaryList from "./DiaryList";
    
    const App = () => {
      const [data, setData] = useState([]);
      const dataId = useRef(0);
      const onCreate = (author, content, emotion) => {
        const created_date = new Date().getTime();
        const newItem = {
          author,
          content,
          emotion,
          created_date,
          id: dataId.current,
        };
        dataId.current += 1;
        setData([newItem, ...data]);
      };
      
      const onDelete = (targetId) => {
        const newDiaryList = data.filter((it) => it.id !== targetId);
        setData(newDiaryList);
      };
    
      const onEdit = (targetId, newContent) => {
        setData(
          data.map((it) =>
            it.id === targetId ? { ...it, content: newContent } : it
          )
        );
      };
    
      return (
        <div className="App">
          <DiaryEditor onCreate={onCreate} />
          <DiaryList onEdit={onEdit} onDelete={onDelete} diaryList={data} />
        </div>
      );
    };
    
    export default App;

    <コードの説明>


    1) const onEdit = (targetId, newContent) => { setData( data.map((it) => it.id === targetId ? { ...it, content: newContent } : it ) ); };=関数の変更
    何を修正するか分からないので、propとしてDiaryItemに渡されます.これはDiaryItemが実行する関数なので、修正パラメータの内容を受信する必要があります.
    そこで,どの日記のターゲットIDを修正するか,どのように内容を修正するかのnewContentをパラメータとして入力する.
    setDataを呼び出してデータの値を変更します.
    dataにmapという関数を適用し、各要素が現在のパラメータとして渡されたtargetIdと一致しているかどうかを確認し、trueの場合、元のデータをすべてロードし、内容をnewContentに変更し、falseの場合itを返します.
    mapという名前の組み込み関数は、すべての要素を巡回しながら新しい配列(変更された配列)を作成し、setDataに転送します.
    onEdit関数は、変更ボタンのあるDiaryItemによって呼び出される必要があります.
    2) <DiaryList onEdit={onEdit} onDelete={onDelete} diaryList={data} />=propをサブアセンブリDiaryListに渡す(DiaryListはDiaryItemの親アセンブリ)

    2. DiaryList.js

    import DiaryItem from "./DiaryItem.js";
    const DiaryList = ({ onEdit, onDelete, diaryList }) => {
      return (
        <div className="DiaryList">
          <h2>일기리스트</h2>
          <h4>{diaryList.length}개의 일기가 있습니다.</h4>
          <div>
            {diaryList.map((it) => (
              <DiaryItem key={it.id} {...it} onEdit={onEdit} onDelete={onDelete} />
            ))}
          </div>
        </div>
      );
    };
    
    export default DiaryList;

    <コードの説明>


    1) const DiaryList = ({ onEdit, onDelete, diaryList })=親アプリケーション.jsコンポーネントからonEditをpropとして受信する
    2) <DiaryItem key={it.id} {...it} onEdit={onEdit} onDelete={onDelete} />=サブアイテムDiaryItem.別のpropをjsコンポーネントに渡す

    3. DiaryItem.js⭐️

    import { useRef, useState } from "react";
    👉🏻const DiaryItem = ({
      onEdit,
      onDelete,
      author,
      content,
      created_date,
      emotion,
      id,
    }) => {
      👉🏻const [isEdit, setIsEdit] = useState(false);
      👉🏻const toggleIsEdit = () => setIsEdit(!isEdit);
      👉🏻const [localContent, setLocalContent] = useState(content);
      👉🏻const localContentInput = useRef();
    
      const handleRemove = () => {
        if (window.confirm(`${id + 1}번째 일기를 삭제하시겠습니까?`)) {
          onDelete(id);
        }
      };
      
      👉🏻const handleQuitEdit = () => {
        setIsEdit(false);
        setLocalContent(content);
      };
    
      👉🏻const handleEdit = () => {
        if (localContent.length < 5) {
          localContentInput.current.focus();
          return;
        }
    
        if (window.confirm(`${id + 1}번쨰 일기를 수정하시겠습니까?`)) {
          onEdit(id, localContent);
          toggleIsEdit();
        }
      };
    
      return (
        <div className="DiaryItem">
          <div className="info">
            <span>
              작 성 자 : {author} | 감 정 점 수 : {emotion}
            </span>
            <br />
            <span className="date">
              시 간 : {new Date(created_date).toLocaleString()}
            </span>
            <div className="content">
              👉🏻{isEdit ? (
                <>
                  <textarea
                    ref={localContentInput}
                    value={localContent}
                    onChange={(e) => setLocalContent(e.target.value)}
                  />
                </>
              ) : (
                <>{content}</>
              )}
            </div>
    
            👉🏻{isEdit ? (
              <>
                <button onClick={handleQuitEdit}>수 정 취 소</button>
                <button onClick={handleEdit}>수 정 완 료 </button>
              </>
            ) : (
              <>
                <button onClick={toggleIsEdit}>수 정 하 기</button>
                <button onClick={handleRemove}>삭 제 하 기</button>
              </>
            )}
          </div>
        </div>
      );
    };
    
    export default DiaryItem;

    <コードの説明>


    1) const DiaryItem = ({onEdit, onDelete, author, content, created_date, emotion, id})=親DiaryListからpropからのonEdit関数を受信して呼び出す

    1.ボタンの変更機能


    1) const [isEdit, setIsEdit] = useState(false);=userStateでfalse勘定科目isEditとしてデフォルト設定されているロールにはtrue、falseブール値があり、変更中か未変更のステータスがブール値であることを示します.
    isEditがtrueの場合は、以下のJSXで修正中と見なして「修正解除」、「修正完了」ボタンにコードを記述し、「falseに変更」でない場合は「修正」または「削除」ボタンとします.
    つまり、修正しているかどうかを示すコード!
    2) {isEdit ? ( <> <button onClick={handleQuitEdit}>수 정 취 소</button> <button onClick={handleEdit}>수 정 완 료 </button> </> ) : ( <> <button onClick={toggleIsEdit}>수 정 하 기</button> <button onClick={handleRemove}>삭 제 하 기</button> </> )}=変更、削除ボタンのみが元の場所で3つの演算子を使用して変更を行った場合、変更を取り消し、変更ボタンを完了/変更でなければ、変更、削除ボタンとして追加されるコード.
    3) const toggleIsEdit = () => setIsEdit(!isEdit);=toggleEdit関数は、呼び出し時にIssetisEditを呼び出し、元のisEditが持つ値をnot演算で反転します.これは「修正」ボタンをクリックしたときに発生する関数です!!
    3) {isEdit ? ( <> <textarea ref={localContentInput} value={localContent} onChange={(e) => setLocalContent(e.target.value)} /> </> ) : ( <>{content}</> )}=isEditと3つの演算子の使用
    trueの場合はtextareaをlocalContentにインポートし、イベント(修正)が発生した場合はsetLocalContentに変更内容を渡すことでlocalContentを更新します.
    falseの場合は、{content}がそのまま表示されます.
    4) const [localContent, setLocalContent] = useState(content);=localContentのuseState初期値をcontentに変更すると、[修正](Modify)ボタンをクリックしたときに作成された内容が表示されます.
    💥しかし、これさえあれば、修正をクリックし、修正してからキャンセルをクリックすると、本来修正したい内容が再現されます.それを防ぐためにhandleQuitEditという関数を作成します.△話をするより、次のような間違った写真を参考にしたほうがいいです.




    もう一度修正をクリックすると、以前に作成した内容が残したエラーを表示できます.

    2.ボタンの変更をキャンセルする機能


    1) const handleQuitEdit = () => { setIsEdit(false); setLocalContent(content); };=handleQuitEdit修正を終了するときに発生する関数
    この関数を呼び出すとsetisEditはfalse(変更なし)になり、setLocalContentを使用してlocalContent値をcontentに変更します.(変更中のフォームはlocalContentによって管理されます!)
    この関数をonClickイベントに挿入して、[修正をキャンセル](Cancel Modification)ボタンをクリックしたときに実行します.

    3.修正ボタンの機能完了


    1) const localContentInput = useRef();=localContentInputは、textareaに注目するので、以下に指定した内容をマークします.
    2) {isEdit ? ( <> <textarea ref={localContentInput} value={localContent} onChange={(e) => setLocalContent(e.target.value)} /> </> ) : ( <>{content}</> )}=textareaラベルにref機能を追加します.
    2) const handleEdit = () => { if (localContent.length < 5) { localContentInput.current.focus(); return; }・𐥊・${id+1}本稼働日を変更しますか?if (window.confirm( )) { onEdit(id, localContent); toggleIsEdit(); }=handleEdit関数は呼び出さなければならない」
    focus機能を提供するにはDOM要素を指定する必要がありますのでref機能が必要です.
    (上端};書き忘れないように)

    🥲私の質問


    localContent.current.focus();もう少しでそう書くところだった
    さらによく考えてみるとlocalContentは修正内容であり、内容が含まれているところに焦点を当てるべきなので、内容が含まれているtextareaでrefを行うべきです.本当に腹立たしいですね.一つ一つのコードをよく考えなければなりません.忘れないでください.

    🖥コード補完画面



    日記作成完了ステータス

    変更中のステータス

    [修正完了]ボタンをクリックします

    変更されたステータス
    <不満な点は修正時間が変わらないこと…?>

    🚀参考資料


    反応講義-李正煥講義