TIL

2024.01.23 TIL #typeof 연산자 #isNaN() #props #객체업데이트

inz1234 2024. 1. 24. 00:55

1. typeof 연산자는 항상 문자열을 반환한다.

따라서, typeof 3 === number 은 항상 "false"를 반환한다.

 

 

2. 숫자인지 여부를 확인하기 위해서는 isNaN() 메서드를 이용해야 한다.

- isNaN()은 값이 NaN일 때 "true"를 반환하고, 숫자일 때 "false"를 반환한다.

 

 

3. Javascript에서 NaN과 다른 값과의 비교는 불가능하다. NaN은 자기자신과 동등하지 않다고 판단한다.

예를 들어,

let arr = ["a", 2, 3, 4],

const  found = arr .find((e) => isNaN(e)) 를 해서 

found 라는 변수에 "a" 라는 문자가 담겼을 때, 즉 isNaN("a")가 true 일 때,

if (a === NaN) 

의 결과가 뭐라고 예상하는가?

 

- 나는 true라고 예상했다.

- 하지만, NaN은 직접적으로 비교가 불가하기 때문에 if (a === NaN) 는 항상 false를 반환한다.

따라서 if (a !== undefined) 라고 해야한다.

 

 

4. form 태그

- 안에 input 태그가 있고 button 태그가 있을 때, button 태그에 <button type="submmit" ~~> 을 써 주면, 그 버튼을 안 눌러도 엔터만 치면 입력이 된다.

- form 태그는 reset() 메서드 제공한다.

  e.target.reset()를 하면  input 태그가 비워진다.

 

 

5. id를 generate 하는 법 

- crypto.randomUUID
- Date.now()
- shortId

 

 

6. 1rem = 16px

 

 

7. 두 컴포넌트가 거의 비슷하고 특정 부분만 다를 때, 그 다른 부분만 props로 넘겨서 하나의 컴포넌트로 묶을 수 있다.

 
 <h2>Working</h2>
        {todolist
          .filter((a) => a.isDone === false)
          .map((todo) => {
            return (
              <div key={todo.id}>
                <h3>{todo.title}</h3>
                <h4>{todo.content}</h4>
                <button onClick={() => deleteBtn(todo.id)}>삭제하기</button>
                <button onClick={() => doneOrCancelBtn(todo.id)}>완료</button>
              </div>
            );
          })}
      </div>
      <div>
        <h2>Done</h2>
        {todolist
          .filter((a) => a.isDone === true)
          .map((todo) => {
            return (
              <div key={todo.id}>
                <h3>{todo.title}</h3>
                <h4>{todo.content}</h4>
                <button onClick={() => deleteBtn(todo.id)}>삭제하기</button>
                <button onClick={() => doneOrCancelBtn(todo.id)}>취소</button>
              </div>
            );
          })}
 

 

이 예시에서는 <h2>Working</h2> 이 부분과 

 .filter((a=> a.isDone === false이 부분만 빼고는 거의 비슷한 구조를 가지고 있다.

따라서 컴포넌트로 분리할 때 이 부분들을 props로 넘길 수 있다.
나는 now 와 isActive라는 키로 자식 컴포넌트에 props를 넘겼다.

function MakeCards({ now, todolist, deleteBtn, doneOrCancelBtn, isActive }) {
  return (
    <div className="todoCards">
      <h2>{now}</h2>
      {todolist
        .filter((a) => a.isDone === isActive)
        .map((todo) => {
          return (
            <div key={todo.id} className="cards">
              <h3>{todo.title}</h3>
              <h4>{todo.content}</h4>
              <div className="buttonBox">
                <button onClick={() => deleteBtn(todo.id)} className="btn">
                  삭제하기
                </button>
                <button
                  onClick={() => doneOrCancelBtn(todo.id)}
                  className="btn"
                >
                  {todo.isDone ? "삭제" : "완료"}
                </button>
              </div>
            </div>
          );
        })}
    </div>
  );
}

 

<MakeCards
        now="Working ✍🏼"
        todolist={todolist}
        deleteBtn={deleteBtn}
        doneOrCancelBtn={doneOrCancelBtn}
        isActive={false}
      />
 
<MakeCards
        now="Done 🙌🏻"
        todolist={todolist}
        deleteBtn={deleteBtn}
        doneOrCancelBtn={doneOrCancelBtn}
        isActive={true}
      />
   

 

 

8. 객체의 기존 속성들은 그대로 가져오면서 새로운 속성을 추가하거나 기존 속성을 업데이트하고자 할 때

 
  const doneOrCancelBtn = (id) => {
    const newlist = todolist.map((todo) => {
      if (id === todo.id) {
        return { ...todo, isDone: !todo.isDone };
      } else {
        return todo;
      }
    });
    setTodolist(newlist);
  };
 

 

- 이 코드의  { ...todoisDone: ! todo.isDone };  이 부분에서 난 처음에 todo 라는 애 자체도

{
      id: Date.now(),
      title: title,
      content: content,
      isDone: false,
    };

 

이런 객체인데, 여기도 마지막에 isDone: false가 있는데 저렇게 바로 뒤에 isDone: todo.isDone }; 이렇게 붙이면, 

이건 바뀌는 게 아니라 그냥

{
      id: Date.now(),
      title: title,
      content: content,
      isDone: false,
      isDone: !todo.isDone,
    };

 

이렇게 추가되는 거 아닌가? 싶었다.

하지만 저 쓰임법은

"객체의 기존 속성들을 그대로 가져오면서 새로운 속성을 추가하거나 기존 속성을 업데이트할 때 사용되는 기법" 이라고 한다.

즉, 저기서는 만약 todo 객체에 이미 isDone 속성이 있다면, ...todo, isDone: true로 인해 기존 값이 덮어씌워지는 것이다.

 

 

9 . JSX 구역 내 중괄호의 쓰임

 
 function MakeCards({ now, todolist, deleteBtn, doneOrCancelBtn, isActive }) {
  return (
    <div className="todoCards">
      <h2>{now}</h2>
      {todolist
        .filter((a) => a.isDone === isActive)
        .map((todo) => {
          return (
            <div key={todo.id} className="cards">
              <h3>{todo.title}</h3>
              <h4>{todo.content}</h4>
              <div className="buttonBox">
                <button onClick={() => deleteBtn(todo.id)} className="btn">
                  삭제하기
                </button>
                <button
                  onClick={() => doneOrCancelBtn(todo.id)}
                  className="btn"
                >
                  {todo.isDone ? "삭제" : "완료"}
                </button>
              </div>
            </div>
          );
        })}
    </div>
  );
}

 

위 코드에서 { todolist.filter(a)~~ 에 쓰이는 중괄호는 JSX 구역에서 javascript를 써야해서 중괄호를 써줘야 하는 건 알겠는데, 밑에 { todo.isDone ? "삭제" : "완료" } 이 부분에서도 중괄호를 써줘야 하는 이유가 궁금했다.
위에 {todolist.filter ~~ 의 중괄호 안이 아직 닫히지 않았는데 또 써줘야 하나 싶었다.

 

그런데,

 { todo.isDone ? "삭제" : "완료" }  이 때 사용되는 중괄호는 Javsscript 코드여서 사용되는 중괄호가 아니었다.

 JSX 내에서는 JavaScript 코드나, 표현식이나 변수를 출력하기 위해 중괄호를 사용한다.

즉, { todo.isDone ? "삭제" : "완료" }는 삼항 연산자를 사용한 표현식으로, JavaScript 코드를 JSX 내에 삽입하기 위해 사용된 것이 아니라, 삼항 연산자의 결과값(표현식)을 JSX에 삽입하기 위한 것이었다.