[React] 수정 화면 토글, 숫자 기록 5(+ input 태그)

happyyeom·2024년 12월 4일

수정하는 화면 만들기

어느 값에 버튼을 눌렀을 때, 입력란을 띄우는 기능을 구현해보자.

<form>
	<button type ="button">수정완료</button>
</form>

위에서 button태그의 속성으로 type ="button"를 적어준 이유는 button태그는 기본적으로 일반 버튼으로 동작하지만 폼(<form>)태그 안에 있는 버튼은 기본 동작이 제출(type="submit"이 기본값)이다. 그래서 클릭 시 폼이 제출되고 페이지가 새로고침된다. 이를 방지하기 위해

  • type="submit": 폼 데이터를 제출합니다. (기본값)
  • type="button": 아무런 기본 동작이 없으며, 단순히 버튼 역할만 수행합니다.
  • type="reset": 폼 안의 입력 필드를 초기화합니다.

세개의 속성 중 하나인 type="button"를 적어둔 것이다. 만약 이 버튼 태그가 폼 태그로 감싸져있지 않다면 작성하지 않아도 된다.

위 코드의 기본적인 원리는 이렇다.

  • true, false를 저장할 state를 생성
  • JSX를 이용해 평상시에는 기본 제목과 내용을 return하고 if문을 사용해서 생성한 state의 값이 true라면 수정할 수 있는 입력란이 들어있는 태그들을 return한다.
  • state의 기본값은 false로 설정(초기에는 수정화면이 아닌 제목과 내용 그대로를 보여줘야 하기에), 수정 버튼을 누르면 state함수로 state값을 true로 설정 -> 수정화면이 보여진다.
  • 수정화면의 수정완료 버튼이나 수정취소 버튼을 누르면 state함수로 state값을 false로 설정 -> 수정화면이 보여지지 않는다.

input 태그

<input />는 사용자로부터 데이터를 입력받기 위한 대화형 컨트롤을 나타낸다. 이 태그는 여러가지 속성 값을 통해 입력 필드의 동작을 세부적으로 조정할 수 있다.
자세한 내용과 속성들은 아래 내용에 잘 정리되어 있다.

HTML <input /> 태그 – 올바른 이해와 사용 방법
https://codingeverybody.kr/html-input-%ED%83%9C%EA%B7%B8-%EC%98%AC%EB%B0%94%EB%A5%B8-%EC%9D%B4%ED%95%B4%EC%99%80-%EC%82%AC%EC%9A%A9-%EB%B0%A9%EB%B2%95/

숫자 기록에 적용하기


이제 수정 코드를 활용하여 기록한 숫자들을 수정할 수 있도록 숫자 기록 코드에 적용해보자.


위 코드는 맨 위에서 작성했던 것처럼 if문으로 return값 자체를 조절하는 방식이고

위 코드는 HTML을 담은 변수 editView와 readView를 만들어 삼항연산자로 바인딩하는 방식이다.

{ editModeStatus ? editView : readView }

이제 입력란의 숫자가 변경될 수 있도록 코드를 개선해보자.

<input />의 onChange 이벤트를 사용해야 하는데, onChange 이벤트는 입력필드의 값을 변경할때 발생하는 이벤트이다.

기본적으로
<input type="text" onChange={handleInputChange} />
1. 사용하고 싶은 함수명을 바로 적어줘도 되고,
2. e 매개변수를 <input />안에서 바로 사용도 가능하다.

<input
            type="text"
            name="username"
            value={username}
            onChange={(event) => setUsername(event.target.value)}
            required
          />

이런식으로 말이다.
이를 기반으로 NumberRecorderListItem컴포넌트를 작성해보면 아래와 같다.

const NumberRecorderListItem = ({ index, number, removeRecord }) => {
  /* NumberRecorderList컴포넌트에게서 map()함수에서 사용된 index와 number, APP컴포넌트에서 사용된
  removeRecord(숫자를 삭제하는 함수)를 받아온다. */
  const [inputNumberValue, setInputNumberValue] = useState(number);
  /* <input />안의 숫자 상태를 보여주는 변수이다. 기본값은 우리가 기존 저장해두었던 각각 number이다. */
  const [editModeStatus, setEditModeStatus] = useState(false);
  /* 이 state는 상태에 따라 수정화면(editView)과 그냥화면을(readView)을 보여주는 용도이다. */
  const readView = (
    <>
      <button onClick={() => setEditModeStatus(true)}>수정</button>
      {/*수정버튼을 클릭하면 editModeStatus를 true로 바꾸어 editView를 바인딩하도록 한다.*/}
    </>
  );
  const editView = (
    <>
      <input 
        type="number"
        placeholder="숫자를 입력해주세요"
        min="1"
        value={inputNumberValue}
        onChange={(e) => setInputNumberValue(e.target.value)}
        />
      {/*
        type="number" ----> 숫자를 입력받는다.
        placeholder="숫자를 입력해주세요" ----> 값이 설정되지 않앗을 때,
        "숫자를 입력해주세요" 라는 문구가 나온다.
        min="1" ----> 컨트롤의 최솟값은 1이다.
        value={inputNumberValue} ----> 컨트롤의 초깃값은 inputNumberValue로 한다.
        하지만 inputNumberValue의 초기값이 number이므로 사실상 컨트롤의 초깃값은 number이다.
        onChange={(e) => setInputNumberValue(e.target.value)}
        ----> setInputNumberValue함수로 inputNumberValue의 값을 현재 value값으로 바꾼다.
      */}
      &nbsp;
      <button onClick={() => setEditModeStatus(false)}></button>
      {/*수정완료버튼을 클릭하면 editModeStatus를 false로 바꾸어 readView를 바인딩하도록 한다.*/}
      &nbsp;
      <button onClick={() => setEditModeStatus(false)}>수정취소</button>
      {/*수정취소버튼을 클릭하면 editModeStatus를 false로 바꾸어 readView를 바인딩하도록 한다.*/}
    </>
  );
  return (
    <li>
      <span>
        {index + 1}번 숫자 : {number}
      </span>
      &nbsp;
      <button onClick={() => removeRecord(index)}>삭제</button>
      &nbsp;
      {editModeStatus ? editView : readView}
    </li>
  );
};

하지만 위의 코드는 입력란 안의 숫자가 변경되는 것일뿐 그 변경된 값으로 기록된 숫자가 수정되지는 않는 반쪽짜리 숫자이다.
이제 수정 완료를 누르면 기록된 숫자를 변경하는 함수를 실행하도록 해보자.

<button onClick={modifyNumber}>수정완료</button>

const modifyNumber = () => {
    if (number == inputNumberValue) return;
    /* 만약 기존 기록된 숫자인 number의 값과 입력란의 변경된 숫자인 
    inputNumberValue의 값이 같다면 아무것도 실행하지 않는다.*/
    /* 만약 두 값이 다르다면 */
    setNumbers(numbers.map((_number,_index) => _index == index ? inputNumberValue : _number));
    /*setNumbers로 numbers의 배열을 수정하는데, map()함수를 이용해 새 배열을 생성한다. 
    만약, _index == index ---> 지금 map()함수의 인덱스를 나타내는 _index와
    NumberRecorderList컴포넌트에서 map()으로 넘겨주었던 이 아이템의 index가 
    같다면
    기존 element(_number)의 값을 => inputNumberValue로 만들고
    다르다면 
    기존 element(_number)의 값을 => _number그대로 둔다.
    한마디로 하면 함수가 실행되면
    numbers.map()함수를 실행해 넘어온 index값으로 고칠 배열의 인덱스를 찾아낸후
    그 인덱스와 일치하는 요소를 inputNumberValue, 현재 입력란에 나타나있는 값
    으로 변경한 배열을 다시 setNumbers()함수를 이용해 numbers의 배열로 바꿔주는 것이다.
    */
    setEditModeStatus(false);
    /* editModeStatus의 값을 false로 만들어 readView가 return되도록 한다.*/
  };

마지막으로 입력란의 숫자를 변경했는데 수정취소를 누른경우 다시 수정버튼을 눌렀을 때 입력란의 버튼이 초기화되도록 수정해보자.

profile
🌳🌳🌳🌳🌳🌳🌳🌳🌳🌳🌳🌳🌳🌳

0개의 댓글