생활코딩! React 리액트 프로그래밍

egoing - React - delete

lshjju 2025. 6. 25. 18:19

데이터 삭제 후 홈으로 이동합니다.


else if (mode === "READ") {
    let title,
      body = null;
    for (let i = 0; i < topics.length; i++) {
      if (topics[i].id === id) {
        title = topics[i].title;
        body = topics[i].body;
      }
    }
    content = <Article title={title} body={body}></Article>;
    contextControl = (
      <>
        <li>
          <a
            href={"/update/" + id}
            onClick={(event) => {
              event.preventDefault();
              setMode("UPDATE");
            }}
          >
            Update
          </a>
        </li>
        <li>
          <input
            type="button"
            value="Delete"
            onClick={() => {
              const newTopics = [];
              for (let i = 0; i < topics.length; i++) {
                if (topics[i].id !== id) {
                  newTopics.push(topics[i]);
                }
              }
              setTopics(newTopics);
              setMode("WELCOME");
            }}
          />
        </li>
      </>
    );
  }

 

Completion


contextControl = <>
      <li><a href={'/update/'+id} onClick={event=>{
        event.preventDefault();
        setMode('UPDATE');
      }}>Update</a></li>
      <li><input type="button" value="Delete" onClick={()=>{
        const newTopics = []
        for(let i=0; i<topics.length; i++) {
          if(topics[i].id !== id) {
            newTopics.push(topics[i]);
          }
        }
        setTopics(newTopics);
        setMode('WELCOME');
      }} /></li>
    </>

 

펑션앱 모드리드 콘텐스트콘트롤변수 업데이트링크 아래

 

델리트 유아이는 상세페이지에서만 노출되므로 리드 모드에 추가 합니다.

 

<>

업데이트 링크가 있는 곳에 삭제버튼 태그를 추가해야 합니다.

리액트 변수 내부 태그는 하나의 태그로 정리해야 합니다.

존재하지 않는 태그로 묶습니다.

 

삭제버튼 추가합니다.

삭제는 실행 후 갈 곳이 없으니 버튼이 잘 어울립니다.

 

데이터 삭제 하는 수상한 방법 하나

현재 삭제하려고 선택된 데이터를 제외한 모든 데이터를 모읍니다.

그 데이터를 새로운 데이터로 저장합니다.

그러면 결론적으로 선택된 데이터만 삭제된 데이터가 생깁니다.

그 데이터를 챙기면 결과적으로 삭제입니다.

수상합니다.

// 'READ' 모드일 때만 표시되는 'Update' 링크와 'Delete' 버튼을 생성합니다.
    // React.Fragment (<>)를 사용하여 여러 요소를 묶을 수 있습니다.
    contextControl = (
      <>
        <li>
          {/* 'Update' 링크 클릭 시 모드를 'UPDATE'로 변경합니다. */}
          <a
            href={"/update/" + id}
            onClick={(event) => {
              event.preventDefault(); // 기본 이벤트(페이지 이동)를 막습니다.
              setMode("UPDATE"); // 모드를 'UPDATE'로 변경합니다.
            }}
          >
            Update
          </a>
        </li>
        <li>
          {/* 'Delete' 버튼 클릭 시 현재 선택된 게시물을 목록에서 삭제합니다. */}
          <input
            type="button"
            value="Delete"
            onClick={() => {
              const newTopics = []; // 삭제된 토픽이 제외된 새로운 토픽 배열을 생성할 빈 배열입니다.
              // 'topics' 배열을 순회하며 현재 'id'와 일치하지 않는 토픽들만 새로운 배열에 추가합니다.
              for (let i = 0; i < topics.length; i++) {
                if (topics[i].id !== id) {
                  newTopics.push(topics[i]);
                }
              }
              setTopics(newTopics); // 업데이트된 토픽 배열로 상태를 변경합니다. (불변성 유지)
              setMode("WELCOME"); // 삭제 후 'WELCOME' 모드로 돌아갑니다.
            }}
          />
        </li>
      </>
    );
  }

test

상세페이지에서 삭제버튼 탭하면 삭제되는지 체크 합니다.


Completion

import "./styles.css";
import { useState } from "react";

function Header(props) {
  console.log("props", props.title);
  return (
    <header>
      <h1>
        <a
          href="/"
          onClick={(event) => {
            event.preventDefault();
            props.onChangeMode();
          }}
        >
          {props.title}
        </a>
      </h1>
    </header>
  );
}

function Nav(props) {
  const lis = [];
  for (let i = 0; i < props.topics.length; i++) {
    let t = props.topics[i];
    lis.push(
      <li key={t.id}>
        <a
          id={t.id}
          href={"/read/" + t.id}
          onClick={(event) => {
            event.preventDefault();
            props.onChangeMode(Number(event.target.id));
          }}
        >
          {t.title}
        </a>
      </li>
    );
  }
  return (
    <nav>
      <ol>{lis}</ol>
    </nav>
  );
}

function Article(props) {
  return (
    <article>
      <h2>{props.title}</h2>
      {props.body}
    </article>
  );
}

function Create(props) {
  return (
    <article>
      <h2>Create</h2>
      <form
        onSubmit={(event) => {
          event.preventDefault();
          const title = event.target.title.value;
          const body = event.target.body.value;
          props.onCreate(title, body);
        }}
      >
        <p>
          <input type="text" name="title" placeholder="title" />
        </p>
        <p>
          <textarea name="body" placeholder="body"></textarea>
        </p>
        <p>
          <input type="submit" value="Create"></input>
        </p>
      </form>
    </article>
  );
}

function Update(props) {
  const [title, setTitle] = useState(props.title);
  const [body, setBody] = useState(props.body);
  return (
    <article>
      <h2>Update</h2>
      <form
        onSubmit={(event) => {
          event.preventDefault();
          const title = event.target.title.value;
          const body = event.target.body.value;
          props.onUpdate(title, body);
        }}
      >
        <p>
          <input
            type="text"
            name="title"
            placeholder="title"
            value={title}
            onChange={(event) => {
              setTitle(event.target.value);
            }}
          />
        </p>
        <p>
          <textarea
            name="body"
            placeholder="body"
            value={body}
            onChange={(event) => {
              setBody(event.target.value);
            }}
          ></textarea>
        </p>
        <p>
          <input type="submit" value="Update"></input>
        </p>
      </form>
    </article>
  );
}

export default function App() {
  const [mode, setMode] = useState("WELCOME");
  const [id, setId] = useState(null);
  const [nextId, setNextId] = useState(4);
  const [topics, setTopics] = useState([
    { id: 1, title: "html", body: "html is ..." },
    { id: 2, title: "css", body: "css is ..." },
    { id: 3, title: "javascript", body: "javascript is ..." },
  ]);
  let content = null;
  let contextControl = null;
  if (mode === "WELCOME") {
    content = <Article title="Welcome" body="Hello, Web"></Article>;
  } else if (mode === "READ") {
    let title,
      body = null;
    for (let i = 0; i < topics.length; i++) {
      if (topics[i].id === id) {
        title = topics[i].title;
        body = topics[i].body;
      }
    }
    content = <Article title={title} body={body}></Article>;
    contextControl = (
      <>
        <li>
          <a
            href={"/update/" + id}
            onClick={(event) => {
              event.preventDefault();
              setMode("UPDATE");
            }}
          >
            Update
          </a>
        </li>
        <li>
          <input
            type="button"
            value="Delete"
            onClick={() => {
              const newTopics = [];
              for (let i = 0; i < topics.length; i++) {
                if (topics[i].id !== id) {
                  newTopics.push(topics[i]);
                }
              }
              setTopics(newTopics);
              setMode("WELCOME");
            }}
          />
        </li>
      </>
    );
  } else if (mode === "CREATE") {
    content = (
      <Create
        onCreate={(_title, _body) => {
          const newTopic = { id: nextId, title: _title, body: _body };
          const newTopics = [...topics];
          newTopics.push(newTopic);
          setTopics(newTopics);
          setMode("READ");
          setId(nextId);
          setNextId(nextId + 1);
        }}
      ></Create>
    );
  } else if (mode === "UPDATE") {
    let title,
      body = null;
    for (let i = 0; i < topics.length; i++) {
      console.log(topics[i].id, id);
      if (topics[i].id === id) {
        title = topics[i].title;
        body = topics[i].body;
      }
    }
    content = (
      <Update
        title={title}
        body={body}
        onUpdate={(title, body) => {
          console.log(title, body);
          const newTopics = [...topics];
          const updatedTopic = { id: id, title: title, body: body };
          for (let i = 0; i < newTopics.length; i++) {
            if (newTopics[i].id === id) {
              newTopics[i] = updatedTopic;
              break;
            }
          }
          setTopics(newTopics);
          setMode("READ");
        }}
      ></Update>
    );
  }

  return (
    <div className="App">
      <Header
        title="WEB"
        onChangeMode={() => {
          setMode("WELCOME");
        }}
      ></Header>
      <Nav
        topics={topics}
        onChangeMode={(_id) => {
          setMode("READ");
          setId(_id);
        }}
      ></Nav>
      {content}
      <a
        href="/create"
        onClick={(event) => {
          event.preventDefault();
          setMode("CREATE");
        }}
      >
        Create
      </a>
      {contextControl}
    </div>
  );
}

 


Comment ver

import "./styles.css"; // CSS 스타일을 불러옵니다.
import { useState } from "react"; // React의 useState 훅을 불러옵니다.

/**
 * Header 컴포넌트는 애플리케이션의 제목을 표시하며, 클릭 시 모드를 변경하는 기능을 제공합니다.
 * @param {object} props - 컴포넌트에 전달되는 속성입니다.
 * @param {string} props.title - 헤더에 표시될 제목입니다.
 * @param {function} props.onChangeMode - 제목 클릭 시 호출될 콜백 함수입니다.
 */
function Header(props) {
  // console.log("props", props.title); // (개발용) props.title 값을 콘솔에 출력합니다.
  return (
    <header>
      <h1>
        <a
          href="/"
          onClick={(event) => {
            event.preventDefault(); // 기본 링크 동작(페이지 새로고침)을 방지합니다.
            props.onChangeMode(); // props로 전달받은 onChangeMode 함수를 호출합니다.
          }}
        >
          {props.title}
        </a>
      </h1>
    </header>
  );
}

/**
 * Nav 컴포넌트는 주어진 주제(topics) 목록을 사용하여 내비게이션 리스트를 생성합니다.
 * 각 항목을 클릭하면 해당 주제의 ID를 사용하여 모드를 변경하는 기능을 제공합니다.
 * @param {object} props - 컴포넌트에 전달되는 속성입니다.
 * @param {Array<object>} props.topics - 내비게이션에 표시될 주제 객체들의 배열입니다. 각 객체는 id와 title 속성을 가집니다.
 * @param {function} props.onChangeMode - 내비게이션 항목 클릭 시 호출될 콜백 함수입니다.
 */
function Nav(props) {
  const lis = []; // 리스트 아이템들을 저장할 배열입니다.
  // props로 전달받은 topics 배열을 순회하여 li 태그를 생성합니다.
  for (let i = 0; i < props.topics.length; i++) {
    let t = props.topics[i]; // 현재 주제 객체입니다.
    lis.push(
      <li key={t.id}>
        {" "}
        {/* React에서 리스트 렌더링 시 각 항목의 고유한 key가 필요합니다. */}
        <a
          id={t.id} // 주제의 id를 DOM 요소의 id로 설정합니다.
          href={"/read/" + t.id} // 링크 주소를 설정합니다.
          onClick={(event) => {
            event.preventDefault(); // 기본 링크 동작을 방지합니다.
            // 클릭된 항목의 id를 숫자로 변환하여 onChangeMode 함수에 전달합니다.
            props.onChangeMode(Number(event.target.id));
          }}
        >
          {t.title}
        </a>
      </li>
    );
  }
  return (
    <nav>
      <ol>{lis}</ol> {/* 생성된 리스트 아이템들을 정렬된 목록으로 렌더링합니다. */}
    </nav>
  );
}

/**
 * Article 컴포넌트는 제목과 본문을 포함하는 내용을 표시합니다.
 * @param {object} props - 컴포넌트에 전달되는 속성입니다.
 * @param {string} props.title - 게시글의 제목입니다.
 * @param {string} props.body - 게시글의 본문 내용입니다.
 */
function Article(props) {
  return (
    <article>
      <h2>{props.title}</h2> {/* 게시글의 제목을 표시합니다. */}
      {props.body} {/* 게시글의 본문 내용을 표시합니다. */}
    </article>
  );
}

/**
 * Create 컴포넌트는 새로운 게시글을 생성하기 위한 폼을 렌더링합니다.
 * @param {object} props - 컴포넌트에 전달되는 속성입니다.
 * @param {function(string, string): void} props.onCreate - 폼 제출 시 호출될 콜백 함수입니다. 제목과 본문을 인수로 받습니다.
 */
function Create(props) {
  return (
    <article>
      <h2>Create</h2>
      <form
        onSubmit={(event) => {
          event.preventDefault(); // 폼 제출 시 기본 동작(페이지 새로고침)을 방지합니다.
          // 폼에서 입력된 제목과 본문 값을 가져옵니다.
          const title = event.target.title.value;
          const body = event.target.body.value;
          props.onCreate(title, body); // onCreate 콜백 함수에 제목과 본문을 전달하여 호출합니다.
        }}
      >
        <p>
          <input type="text" name="title" placeholder="title" />{" "}
          {/* 제목 입력 필드입니다. */}
        </p>
        <p>
          <textarea name="body" placeholder="body"></textarea>{" "}
          {/* 본문 입력 필드입니다. */}
        </p>
        <p>
          <input type="submit" value="Create"></input>{" "}
          {/* 폼 제출 버튼입니다. */}
        </p>
      </form>
    </article>
  );
}

/**
 * Update 컴포넌트는 기존 게시글을 수정하기 위한 폼을 렌더링합니다.
 * @param {object} props - 컴포넌트에 전달되는 속성입니다.
 * @param {string} props.title - 수정할 게시글의 현재 제목입니다.
 * @param {string} props.body - 수정할 게시글의 현재 본문입니다.
 * @param {function(string, string): void} props.onUpdate - 폼 제출 시 호출될 콜백 함수입니다. 수정된 제목과 본문을 인수로 받습니다.
 */
function Update(props) {
  // useState 훅을 사용하여 입력 필드의 상태를 관리합니다.
  const [title, setTitle] = useState(props.title); // 현재 제목을 상태로 초기화합니다.
  const [body, setBody] = useState(props.body); // 현재 본문을 상태로 초기화합니다.

  return (
    <article>
      <h2>Update</h2>
      <form
        onSubmit={(event) => {
          event.preventDefault(); // 폼 제출 시 기본 동작(페이지 새로고침)을 방지합니다.
          // 폼에서 입력된 제목과 본문 값을 가져옵니다.
          const title = event.target.title.value;
          const body = event.target.body.value;
          props.onUpdate(title, body); // onUpdate 콜백 함수에 수정된 제목과 본문을 전달하여 호출합니다.
        }}
      >
        <p>
          <input
            type="text"
            name="title"
            placeholder="title"
            value={title} // 입력 필드의 값을 title 상태와 연결합니다.
            onChange={(event) => {
              setTitle(event.target.value); // 입력 필드 변경 시 title 상태를 업데이트합니다.
            }}
          />
        </p>
        <p>
          <textarea
            name="body"
            placeholder="body"
            value={body} // 입력 필드의 값을 body 상태와 연결합니다.
            onChange={(event) => {
              setBody(event.target.value); // 입력 필드 변경 시 body 상태를 업데이트합니다.
            }}
          ></textarea>
        </p>
        <p>
          <input type="submit" value="Update"></input>{" "}
          {/* 폼 제출 버튼입니다. */}
        </p>
      </form>
    </article>
  );
}

/**
 * App 컴포넌트는 전체 애플리케이션의 최상위 컴포넌트입니다.
 * 모드(WELCOME, READ, CREATE, UPDATE)에 따라 다른 내용을 렌더링하고 상태를 관리합니다.
 */
export default function App() {
  // 모드 상태를 관리합니다. 기본값은 "WELCOME"입니다.
  const [mode, setMode] = useState("WELCOME");
  // 현재 선택된 게시글의 ID를 관리합니다.
  const [id, setId] = useState(null);
  // 다음으로 생성될 게시글의 ID를 관리합니다.
  const [nextId, setNextId] = useState(4);
  // 게시글 주제 목록을 관리합니다. 초기 데이터가 포함되어 있습니다.
  const [topics, setTopics] = useState([
    { id: 1, title: "html", body: "html is ..." },
    { id: 2, title: "css", body: "css is ..." },
    { id: 3, title: "javascript", body: "javascript is ..." },
  ]);

  let content = null; // 현재 모드에 따라 렌더링될 메인 콘텐츠입니다.
  let contextControl = null; // 현재 모드에 따라 표시될 추가 제어 요소(예: Update, Delete 버튼)입니다.

  // 현재 모드에 따라 렌더링할 콘텐츠를 결정합니다.
  if (mode === "WELCOME") {
    // "WELCOME" 모드일 경우, 환영 메시지를 담은 Article 컴포넌트를 렌더링합니다.
    content = <Article title="Welcome" body="Hello, Web"></Article>;
  } else if (mode === "READ") {
    // "READ" 모드일 경우, 선택된 ID에 해당하는 게시글 내용을 찾아 Article 컴포넌트로 렌더링합니다.
    let title,
      body = null;
    // topics 배열을 순회하여 현재 id와 일치하는 게시글을 찾습니다.
    for (let i = 0; i < topics.length; i++) {
      if (topics[i].id === id) {
        title = topics[i].title;
        body = topics[i].body;
        break; // 일치하는 항목을 찾으면 반복을 중단합니다.
      }
    }
    content = <Article title={title} body={body}></Article>; // 찾은 게시글 내용을 렌더링합니다.

    // "READ" 모드일 때만 'Update'와 'Delete' 버튼을 표시합니다.
    contextControl = (
      <>
        <li>
          <a
            href={"/update/" + id}
            onClick={(event) => {
              event.preventDefault(); // 기본 링크 동작을 방지합니다.
              setMode("UPDATE"); // 모드를 "UPDATE"로 변경합니다.
            }}
          >
            Update
          </a>
        </li>
        <li>
          <input
            type="button"
            value="Delete"
            onClick={() => {
              // 'Delete' 버튼 클릭 시 현재 게시글을 topics 목록에서 삭제합니다.
              const newTopics = [];
              for (let i = 0; i < topics.length; i++) {
                if (topics[i].id !== id) {
                  // 현재 id와 다른 게시글만 새로운 배열에 추가합니다.
                  newTopics.push(topics[i]);
                }
              }
              setTopics(newTopics); // topics 상태를 업데이트합니다.
              setMode("WELCOME"); // 삭제 후 "WELCOME" 모드로 돌아갑니다.
            }}
          />
        </li>
      </>
    );
  } else if (mode === "CREATE") {
    // "CREATE" 모드일 경우, 새로운 게시글을 생성하는 Create 컴포넌트를 렌더링합니다.
    content = (
      <Create
        onCreate={(_title, _body) => {
          // onCreate 콜백 함수: 새로운 게시글이 생성될 때 호출됩니다.
          const newTopic = { id: nextId, title: _title, body: _body }; // 새 게시글 객체를 생성합니다.
          const newTopics = [...topics]; // 기존 topics 배열을 복사합니다.
          newTopics.push(newTopic); // 새 게시글을 복사된 배열에 추가합니다.
          setTopics(newTopics); // topics 상태를 업데이트합니다.
          setMode("READ"); // 생성 후 "READ" 모드로 전환합니다.
          setId(nextId); // 새로 생성된 게시글의 ID를 현재 선택된 ID로 설정합니다.
          setNextId(nextId + 1); // 다음 게시글 ID를 1 증가시킵니다.
        }}
      ></Create>
    );
  } else if (mode === "UPDATE") {
    // "UPDATE" 모드일 경우, 선택된 게시글의 내용을 가져와 Update 컴포넌트를 렌더링합니다.
    let title,
      body = null;
    // topics 배열을 순회하여 현재 id와 일치하는 게시글을 찾습니다.
    for (let i = 0; i < topics.length; i++) {
      // console.log(topics[i].id, id); // (개발용) 현재 topic의 id와 선택된 id를 콘솔에 출력합니다.
      if (topics[i].id === id) {
        title = topics[i].title;
        body = topics[i].body;
        break; // 일치하는 항목을 찾으면 반복을 중단합니다.
      }
    }
    content = (
      <Update
        title={title} // 현재 게시글의 제목을 Update 컴포넌트에 전달합니다.
        body={body} // 현재 게시글의 본문을 Update 컴포넌트에 전달합니다.
        onUpdate={(_title, _body) => {
          // onUpdate 콜백 함수: 게시글이 수정될 때 호출됩니다.
          const newTopics = [...topics]; // 기존 topics 배열을 복사합니다.
          const updatedTopic = { id: id, title: _title, body: _body }; // 수정된 게시글 객체를 생성합니다.
          for (let i = 0; i < newTopics.length; i++) {
            if (newTopics[i].id === id) {
              newTopics[i] = updatedTopic; // 복사된 배열에서 해당 ID의 게시글을 업데이트합니다.
              break; // 업데이트 후 반복을 중단합니다.
            }
          }
          setTopics(newTopics); // topics 상태를 업데이트합니다.
          setMode("READ"); // 수정 후 "READ" 모드로 전환합니다.
        }}
      ></Update>
    );
  }

  return (
    <div>
      {/* Header 컴포넌트를 렌더링하고, 제목 클릭 시 모드를 "WELCOME"으로 변경합니다. */}
      <Header
        title="WEB"
        onChangeMode={() => {
          setMode("WELCOME");
        }}
      ></Header>
      {/* Nav 컴포넌트를 렌더링하고, topics 배열을 전달하며 항목 클릭 시 모드를 "READ"로 변경하고 해당 id를 설정합니다. */}
      <Nav
        topics={topics}
        onChangeMode={(_id) => {
          setMode("READ");
          setId(_id);
        }}
      ></Nav>
      {/* 현재 모드에 따라 결정된 메인 콘텐츠를 렌더링합니다. */}
      {content}
      <ul>
        <li>
          <a
            href="/create"
            onClick={(event) => {
              event.preventDefault(); // 기본 링크 동작을 방지합니다.
              setMode("CREATE"); // 모드를 "CREATE"로 변경합니다.
            }}
          >
            Create
          </a>
        </li>
        {/* 현재 모드에 따라 결정된 추가 제어 요소(Update/Delete 버튼)를 렌더링합니다. */}
        {contextControl}
      </ul>
    </div>
  );
}