반응형
반응형

📝Reducer

컴포넌트가 복잡해지면 컴포넌트의 state가 업데이트되는 다양한 경우를 한눈에 파악하기 어려워질 수 있습니다

컴포넌트 내부에 있는 state 로직을 컴포넌트 외부의 “reducer”라고 하는 단일 함수로 옮길 수 있습니다

reducer는 state를 다루는 다른 방법입니다

 

useState 사용한 예제

import { useState } from 'react';
import AddTask from './AddTask.js';
import TaskList from './TaskList.js';

export default function TaskApp() {
  const [tasks, setTasks] = useState(initialTasks);

  function handleAddTask(text) {
    setTasks([...tasks, {
      id: nextId++,
      text: text,
      done: false
    }]);
  }

  function handleChangeTask(task) {
    setTasks(tasks.map(t => {
      if (t.id === task.id) {
        return task;
      } else {
        return t;
      }
    }));
  }

  function handleDeleteTask(taskId) {
    setTasks(
      tasks.filter(t => t.id !== taskId)
    );
  }

  return (
    <>
      <h1>Prague itinerary</h1>
      <AddTask
        onAddTask={handleAddTask}
      />
      <TaskList
        tasks={tasks}
        onChangeTask={handleChangeTask}
        onDeleteTask={handleDeleteTask}
      />
    </>
  );
}

let nextId = 3;
const initialTasks = [
  { id: 0, text: 'Visit Kafka Museum', done: true },
  { id: 1, text: 'Watch a puppet show', done: false },
  { id: 2, text: 'Lennon Wall pic', done: false },
];

위 예제를 reducer를 이용해 바꿔보겠습니다

 

state에서 보낼 데이터 정보 추출

function handleAddTask(text) {
  dispatch({
    type: 'added',
    id: nextId++,
    text: text,
  });
}

function handleChangeTask(task) {
  dispatch({
    type: 'changed',
    task: task
  });
}

function handleDeleteTask(taskId) {
  dispatch({
    type: 'deleted',
    id: taskId
  });
}

첫번째 이벤트 리스너에 있는 로직에 필요한 데이터를 선별한 후 dispatch라는 함수를 통해 보내주는 역할만 합니다

여기에서 type으로는 어떤 기능을 할 지 그리고 나머지에는 보내고 싶은 형태로 데이터를 보냅니다

 

 

reducer에 state에서 사용했던 로직 옮기기

function tasksReducer(tasks, action) {
  if (action.type === 'added') {
    return [...tasks, {
      id: action.id,
      text: action.text,
      done: false
    }];
  } else if (action.type === 'changed') {
    return tasks.map(t => {
      if (t.id === action.task.id) {
        return action.task;
      } else {
        return t;
      }
    });
  } else if (action.type === 'deleted') {
    return tasks.filter(t => t.id !== action.id);
  } else {
    throw Error('Unknown action: ' + action.type);
  }
}

type을 보내준 이유는 여기에서 사용하려고 함입니다 여기 예제에서는 if-else문으로 되어있지만 switch-case로 대부분 사용합니다 tasks기존 데이터(initialTasks)가 들어가고 action에서는 dispatch로 보낸 데이터가 들어가게 됩니다

 

useReducer를 이용한 예제로 변경한 코드

import { useReducer } from 'react';
import AddTask from './AddTask.js';
import TaskList from './TaskList.js';

export default function TaskApp() {
  const [tasks, dispatch] = useReducer(
    tasksReducer,
    initialTasks
  );

  function handleAddTask(text) {
    dispatch({
      type: 'added',
      id: nextId++,
      text: text,
    });
  }

  function handleChangeTask(task) {
    dispatch({
      type: 'changed',
      task: task
    });
  }

  function handleDeleteTask(taskId) {
    dispatch({
      type: 'deleted',
      id: taskId
    });
  }

  return (
    <>
      <h1>Prague itinerary</h1>
      <AddTask
        onAddTask={handleAddTask}
      />
      <TaskList
        tasks={tasks}
        onChangeTask={handleChangeTask}
        onDeleteTask={handleDeleteTask}
      />
    </>
  );
}

function tasksReducer(tasks, action) {
  switch (action.type) {
    case 'added': {
      return [...tasks, {
        id: action.id,
        text: action.text,
        done: false
      }];
    }
    case 'changed': {
      return tasks.map(t => {
        if (t.id === action.task.id) {
          return action.task;
        } else {
          return t;
        }
      });
    }
    case 'deleted': {
      return tasks.filter(t => t.id !== action.id);
    }
    default: {
      throw Error('Unknown action: ' + action.type);
    }
  }
}

let nextId = 3;
const initialTasks = [
  { id: 0, text: 'Visit Kafka Museum', done: true },
  { id: 1, text: 'Watch a puppet show', done: false },
  { id: 2, text: 'Lennon Wall pic', done: false }
];

이걸 하나의 코드로 표현하면 위와 같습니다 

 

  • useReducer로 내가 만든 reducer(로직처리 부분)과 초기값을 연결시킵니다
  • dispatch를 통해 해당 reducer로 사용할 값을 보냅니다

 

📝useRef

import { useRef } from 'react';

export default function Form() {
  const inputRef = useRef(null);

  function handleClick() {
    inputRef.current.focus();
  }

  return (
    <>
      <input ref={inputRef} />
      <button onClick={handleClick}>
        Focus the input
      </button>
    </>
  );
}

ref는 참조에 많이 쓰이는 값이며 특징은 아래와 같습니다

  • ref.current을 이용해 해당 ref의 current 값에 접근할 수 있습니다 이 값은 의도적으로 변경할 수 있으며 읽고 쓸 수 있습니다
  • state와 달리 ref를 변경하면 다시 렌더링 되지 않습니다
  • Event Handler에게만 필요한 정보이고 변경이 일어날 때 리렌더링이 필요하지 않다면, ref를 사용하는 것이 더 효율적입니다 (대부분 ref 접근은 이벤트 핸들러 안에서 일어납니다)
  • React가 관리하는 DOM 요소에 접근해야 할 때 사용됩니다

 

import React, { useRef } from 'react';

function MyComponent() {
  const inputRef = useRef(null);

  // 렌더링 중에 ref.current를 읽는 경우
  if (inputRef.current) {
    console.log('렌더링 중에 ref.current를 읽음:', inputRef.current);
  }

  return <input ref={inputRef} />;
}

export default MyComponent;

useRef는 렌더링중에 읽거나 쓰기를 하지 않아야합니다

 

 

 

DOM 여러개 ref로 관리하기

import { useRef, useState } from "react";

export default function CatFriends() {
  const itemsRef = useRef(null);
  const [catList, setCatList] = useState(setupCatList);

  function scrollToCat(cat) {
    const map = getMap();
    const node = map.get(cat);
    node.scrollIntoView({
      behavior: "smooth",
      block: "nearest",
      inline: "center",
    });
  }

  function getMap() {
    if (!itemsRef.current) {
      // 처음 사용하는 경우, Map을 초기화합니다.
      itemsRef.current = new Map();
    }
    return itemsRef.current;
  }

  return (
    <>
      <nav>
        <button onClick={() => scrollToCat(catList[0])}>Tom</button>
        <button onClick={() => scrollToCat(catList[5])}>Maru</button>
        <button onClick={() => scrollToCat(catList[9])}>Jellylorum</button>
      </nav>
      <div>
        <ul>
          {catList.map((cat) => (
            <li
              key={cat}
              ref={(node) => {
                const map = getMap();
                if (node) {
                  map.set(cat, node);
                } else {
                  map.delete(cat);
                }
              }}
            >
              <img src={cat} />
            </li>
          ))}
        </ul>
      </div>
    </>
  );
}

function setupCatList() {
  const catList = [];
  for (let i = 0; i < 10; i++) {
    catList.push("https://loremflickr.com/320/240/cat?lock=" + i);
  }

  return catList;
}

배열값이 있어서 순회하면서 화면에 출력하는데 해당 출력된 값에 ref로 접근해야 할 때 ref안에 useRef를 생성할 수 없기 때문에 useRef에 Map을 넣고  ref에서 node라고 ref정보를 담은 걸 key,value로 담아서 useRef를 관리한다

 

 

 

다른 컴포넌트에서 ref 참조하기

import { forwardRef, useRef } from 'react';

const MyInput = forwardRef((props, ref) => {
  return <input {...props} ref={ref} />;
});

export default function Form() {
  const inputRef = useRef(null);

  function handleClick() {
    inputRef.current.focus();
  }

  return (
    <>
      <MyInput ref={inputRef} />
      <button onClick={handleClick}>
        Focus the input
      </button>
    </>
  );
}

일반적으로 ref만 사용하면 다른 컴포넌트 ref에 접근할 수 없는데 forwordRef를 이용해 다른 컴포넌트의 ref값을 참조할 수 있습니다

 

 

📝useEffect

작동할 내용과 어떤 값을 감시할 지 정합니다 그 후 감시할 값이 변할 경우 useEffect에 작성한 내용이 작동하게 됩니다

변화되었는지에 대해서는 Object.is라는 것을 통해 주소값이 변동되었는지로 감시합니다 그렇기 때문에 감시할 값이 Object인 경우 리렌더링할 때 Object 내용은 같아도 주소값이 계속 변동되기 때문에 바뀌었다고 판단해서 계속적인 리렌더링이 일어날 수 있습니다

 

  1. 기본적으로 Effect는 모든 commit 이후에 실행됩니다
    • 컴포넌트가 렌더링 될 때마다 React는 화면을 업데이트한 다음 useEffect 내부의 코드를 실행합니다 다시 말해, useEffect는 화면에 렌더링이 반영될 때까지 코드 실행을 “지연”시킵니다
  2. 필요한 경우 클린업 함수 추가해서 해제해 줘야합니다

 

useEffect 예제

import { useState, useRef, useEffect } from 'react';

function VideoPlayer({ src, isPlaying }) {
  const ref = useRef(null);

  // isPlaying 값이 변경되었다는 걸 감지했을 때 동작
  useEffect(() => {
    if (isPlaying) {
      console.log('video.play() 호출');
      ref.current.play();
    } else {
      console.log('video.pause() 호출');
      ref.current.pause();
    }
  }, [isPlaying]);

  return <video ref={ref} src={src} loop playsInline />;
}

export default function App() {
  const [isPlaying, setIsPlaying] = useState(false);
  const [text, setText] = useState('');
  return (
    <>
      <input value={text} onChange={e => setText(e.target.value)} />
      <button onClick={() => setIsPlaying(!isPlaying)}>
        {isPlaying ? '일시 정지' : '재생'}
      </button>
      <VideoPlayer
        isPlaying={isPlaying}
        src="https://interactive-examples.mdn.mozilla.net/media/cc0-videos/flower.mp4"
      />
    </>
  );
}

useEffect은 어떤 값이 변화되었다는 걸 감지해서 감지했을 때 안에 있는 익명함수를 실행시킵니다

 

useEffect 사용 방법

useEffect(() => {
  // 모든 렌더링 후에 실행됩니다
});

useEffect(() => {
  // 마운트될 때만 실행됩니다 (컴포넌트가 나타날 때)
}, []);

useEffect(() => {
 // 마운트될 때 실행되며, *또한* 렌더링 이후에 a 또는 b 중 하나라도 변경된 경우에도 실행됩니다
}, [a, b]);

 

useEffect 클린업

/** 커넥션 해제 **/
useEffect(() => {
  const connection = createConnection();
  connection.connect();
  return () => {
    connection.disconnect();
  };
}, []);

/** 애니메이션 해제 **/
useEffect(() => {
  function handleScroll(e) {
    console.log(window.scrollX, window.scrollY);
  }
  window.addEventListener('scroll', handleScroll);
  return () => window.removeEventListener('scroll', handleScroll);
}, []);

useEffect가 어떤 것을 구독한다면, 클린업 함수에서 구독을 해지해야 합니다

예를 들면 useEffect가 어떤 요소를 애니메이션으로 표시하는 경우, 클린업 함수에서 애니메이션을 초기 값으로 재설정해야 합니다

 

 

클린업 예제

function App() {

    const [data,setData]= useState();
    const [input, setInput] = useState('')


    /** clean-up 미사용 **/
    // useEffect(()=> {
    //
    //     const getData = async () => {
    //         const resp = await fetch('https://api.sampleapis.com/coffee/hot');
    //         const json = await resp.json();
    //         setData(json[0][input]);
    //     }
    //     getData();
    //
    // },[input])

    useEffect(()=> {
        let ignore = false;

        const getData = async () => {
            const resp = await fetch('https://api.sampleapis.com/coffee/hot');
            const json = await resp.json();
            if (!ignore) {
                setData(json[0][input]);
            }

        }

        getData();

        return () => {
            ignore = true;
        };

    },[input])

    return (
        <div>
            {data}
            <br/>
            <select onChange={(e)=>{setInput(e.target.value)}}>
                <option value="title">title</option>
                <option value="description">description</option>
            </select>
        </div>

    );

}

 

DataFetch가 있고 그 이후 그 데이터를 JSX로 보여주는데 동작과정은 아래와 같다

  • useId 변경 → 언마운트로 ignore true 동작 → DataFetch → setData로 리렌더링

 

fetch에서 clean-up 작업을 한 이유는 예를 들면 네트워크가 안 좋은데 select box를 엄청나게 바꾸면 네트워크 요청은 여러개가 나가고 리렌더링작업은 큐처럼 쌓이게 되어 뒤늦게 {data}가 큐에 쌓인대로 API요청한 회수만큼 와따가따하게 된다 clean-up 작업을 한 경우는 언마운트시 작동함으로 전 네트워크 요청에 대해서 ignore true값을 줘서 리렌더링 안 하게 한다

 

동작 과정은 아래와 같다

  • Select box 변경 → 1번 네트워크 요청 → 1번 네트워크 요청중에 Select box 또 변경 → 1번 네트워크 요청 결과를 await중에 clean-up 내용 작동으로 ignore가 true로 변경되어서 데이터 받아와도 setData 작동 안 해서 변경 없음 → 2번 네트워크 요청 await후 input의 변경이 없기 때문에 ignore은 false상태이기 때문에 리렌더링이 된다

 

useEffect 사용할 때 주의할 점이 있다

  • useEffect의 경우 렌더링 된 이후에 작동하기 때문에 렌더링 전에 작동시켜야하면 서버사이드에서 해결해줘야한다
  • useEffect만 사용해서 데이터를 fetch하는 경우 미리 데이터를 로드하거나 캐시하지 않기 때문에 느릴 수도 있다

위와 같은 문제점을 해결하기 위해서는 일반적으로 프레임워크에 있는 내장 데이터 패칭기능이나 오픈 소스 솔루션인 React Query, useSWR를 사용하면 네트워크 응답을 캐싱하며 네트워크를 기본적으로 최적화하니 사용하는게 좋다

 

 

useEffect 잘 사용하기

function TodoList({ todos, filter }) {
  const [newTodo, setNewTodo] = useState('');

  // 🔴 피하세요: 중복된 state 및 불필요한 효과
  const [visibleTodos, setVisibleTodos] = useState([]);
  useEffect(() => {
    setVisibleTodos(getFilteredTodos(todos, filter));
  }, [todos, filter]);

  // ...
}

function TodoList({ todos, filter }) {
  const [newTodo, setNewTodo] = useState('');
  // ✅ getFilteredTodos()가 느리지 않다면 괜찮습니다.
  const visibleTodos = getFilteredTodos(todos, filter);
  // ...
}

import { useMemo, useState } from 'react';

function TodoList({ todos, filter }) {
  const [newTodo, setNewTodo] = useState('');
  const visibleTodos = useMemo(() => {
    // ✅ todos 또는 filter가 변경되지 않는 한 다시 실행되지 않습니다.
    return getFilteredTodos(todos, filter);
  }, [todos, filter]);
  // ...
}

props의 todos랑 filter랑 변경되면서 다시 해당 함수인 TodoList를 실행하기 때문에 굳이 state로 관리할필요 없고 필요사항에만 메모이제이션해서 계산하게 하면 더욱 좋다

 

  • 어떤 경우 메모이제이션을 해야할까?
    • 전체적으로 기록된 시간이 상당한 양(예: 1ms 이상)으로 합산되면 해당 계산을 메모이제이션하는 것이 좋습니다가장 정확한 시간을 얻으려면 프로덕션용 앱을 빌드하고 사용자가 사용하는 것과 같은 기기에서 테스트해야합니다

 

function App() {
    const [firstName, setFirstName] = useState('Taylor');
    const [lastName, setLastName] = useState('Swift');
    // 위 useState 값이 변경되면서 전체를 실행하기 때문에 state로 상태관리를 할 필요도 없다
    const fullName = firstName + ' ' + lastName; 
    
    // 🔴 피하세요: 중복된 state 및 불필요한 Effect
    //const [fullName, setFullName] = useState('');
    //useEffect(() => {
    //    setFullName(firstName + ' ' + lastName);
    //}, [firstName, lastName]);

    return (
        <div>
            <input type="text" onChange={(e)=>setFirstName(e.target.value)} />
            <input type="text" onChange={(e)=>setLastName(e.target.value)} />
            {fullName}
        </div>
    );
}

입력따위로 set하는 경우가 따로 있지 않는 경우는 state로 만들 필요가 없다

 

// ProfilePage 컴포넌트: userId를 prop으로 받아서 Profile 컴포넌트에 전달
function ProfilePage({ userId }: {userId:string}) {
    return (
        <Profile
            userId={userId}
            key={userId} // userId가 변경될 때마다 새로운 Profile 컴포넌트가 마운트됨
        />
    );
}

// Profile 컴포넌트: userId를 prop으로 받아서 사용
function Profile({ userId }:{userId:string}) {
    const [comment, setComment] = useState('');

    return (
        <div>
            <h1>Profile for user: {userId}</h1>
            <textarea
                value={comment}
                onChange={(e) => setComment(e.target.value)}
                placeholder="Leave a comment"
            />
        </div>
    );
}



function App() {
    const [userId, setUserId] = useState('user1');

    return (
        <div>
            <button onClick={() => setUserId('user1')}>User 1</button>
            <button onClick={() => setUserId('user2')}>User 2</button>
            <ProfilePage userId={userId}  />
        </div>
    );
}

userId값이 바뀌어서 props값이 달라지면서 리렌더링이 되는데 일반적으로 React는 동일한 컴포넌트가 같은 위치에 렌더링 될 때 state를 보존하기 때문에 comment값은 초기화가 안 됩니다 그렇기 때문에 key를 이용해 서로 다른 컴포넌트라는 걸 인식시켜줘야합니다

 

일반적으로 props가 계속 바뀌면 key 설정을 해주는게 맞습니다

 

function List({ items }: {items: Array<any>}) {
    // const [selection, setSelection] = useState<any>(null);

    // 🔴 피하세요: Effect에서 prop 변경 시 state 조정하기 (방법1)
    // useEffect(() => {
    //     setSelection(null);
    // }, [items]);

    // 더 좋습니다: 렌더링 중 state 조정 (방법2)
    // const [prevItems, setPrevItems] = useState(items);
    // if (items !== prevItems) {
    //     setPrevItems(items);
    //     setSelection(null);
    // }

    // return (
    //     <div>
    //         <ul>
    //             {items.map(item => (
    //                 <li key={item.id} onClick={() => setSelection(item)}>
    //                     {item.name}
    //                 </li>
    //             ))}
    //         </ul>
    //         <div>
    //             Selected: {selection ? selection.name : 'None'}
    //         </div>
    //     </div>
    // );

    const [selectedId, setSelectedId] = useState(null);

    // ✅ 최고예요: 렌더링 중에 모든 것을 계산 (방법3)
    const selection = items.find(item => item.id === selectedId) ?? null;


    return (
        <div>
            <ul>
                {items.map(item => (
                    <li key={item.id} onClick={() => setSelectedId(item.id)}>
                        {item.name}
                    </li>
                ))}
            </ul>
            <div>
                Selected: {selection ? selection.name : 'None'}
            </div>
        </div>
    );
}

function App() {
    const [items, setItems] = useState(items1);

    return (
        <div>
            <button onClick={() => setItems(items1)}>Set Items 1</button>
            <button onClick={() => setItems(items2)}>Set Items 2</button>
            <List items={items}/>
        </div>
    );

}

key 설정을 따로 못하는 경우 같은 위치 컴포넌트의 state 초기화 시켜야할 때는 위와 같은 방법을 이용할 수 있습니다

 

/** bad code **/
function Game() {
  const [card, setCard] = useState(null);
  const [goldCardCount, setGoldCardCount] = useState(0);
  const [round, setRound] = useState(1);
  const [isGameOver, setIsGameOver] = useState(false);

  // 🔴 피하세요: 서로를 트리거하기 위해서만 state를 조정하는 Effect 체인
  useEffect(() => {
    if (card !== null && card.gold) {
      setGoldCardCount(c => c + 1);
    }
  }, [card]);

  useEffect(() => {
    if (goldCardCount > 3) {
      setRound(r => r + 1)
      setGoldCardCount(0);
    }
  }, [goldCardCount]);

  useEffect(() => {
    if (round > 5) {
      setIsGameOver(true);
    }
  }, [round]);

  useEffect(() => {
    alert('Good game!');
  }, [isGameOver]);

  function handlePlaceCard(nextCard) {
    if (isGameOver) {
      throw Error('Game already ended.');
    } else {
      setCard(nextCard);
    }
  }

  // ...
  
  
  /** right code **/
  function Game() {
  const [card, setCard] = useState(null);
  const [goldCardCount, setGoldCardCount] = useState(0);
  const [round, setRound] = useState(1);

  // ✅ 렌더링 중에 가능한 것을 계산합니다.
  const isGameOver = round > 5;

  function handlePlaceCard(nextCard) {
    if (isGameOver) {
      throw Error('Game already ended.');
    }

    // ✅ 이벤트 핸들러에서 다음 state를 모두 계산합니다.
    setCard(nextCard);
    if (nextCard.gold) {
      if (goldCardCount <= 3) {
        setGoldCardCount(goldCardCount + 1);
      } else {
        setGoldCardCount(0);
        setRound(round + 1);
        if (round === 5) {
          alert('Good game!');
        }
      }
    }
  }

  // ...

웬만해서 Effect를 남발하지말고 Effect 없이 해결할 수 있는지 파악한다 그리고 같은 맥락의 있는 경우 Effect를 하나로 묶어주는게 더 좋다 위 예시는 여러 개의 useEffect 훅을 사용하여 상태 업데이트를 체이닝하면 비효율적이고 유지보수가 어려운 코드를 만들 수 있다는 것을 보여줍니다

 

import React from 'react';

function Toggle({ isOn, onChange }) {
  function handleClick() {
    onChange(!isOn);
  }

  function handleDragEnd(e) {
    if (isCloserToRightEdge(e)) {
      onChange(true);
    } else {
      onChange(false);
    }
  }

  return (
    <div>
      <button onClick={handleClick}>{isOn ? 'ON' : 'OFF'}</button>
      <div
        onDragEnd={handleDragEnd}
        style={{ width: '100px', height: '100px', backgroundColor: 'lightgray' }}
      />
    </div>
  );
}

export default Toggle;


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

function App() {
  const [isOn, setIsOn] = useState(false);

  function handleToggleChange(nextIsOn) {
    setIsOn(nextIsOn);
  }

  return (
    <div>
      <Toggle isOn={isOn} onChange={handleToggleChange} />
      <div>Toggle is {isOn ? 'ON' : 'OFF'}</div>
    </div>
  );
}

export default App;

자식이 부모에게 명령을 내리거나 데이터를 전달하려면 부모로부터 제어권(props)들을 넘겨받아야한다

 

 

반응형
반응형

📝 비농업고용지수

농축산업을 제외한 전월 고용인구수 변화를 측정합니다 이걸로 경제 활동하고있는 사람들에 대해서 알 수 있습니다

 

https://kr.investing.com/economic-calendar/nonfarm-payrolls-227

 

미국 비농업고용지수

비농업고용지수 같은 주요 경제 이벤트 및 글로벌 마켓에 미치는 그 영향력을 실시간으로 확인하세요.

kr.investing.com

 

📝실업수당청구건수

실업 보험에 가입한 개인의 수를 측정합니다 청구건수가 증가하면 경기가 나쁘다는 걸로 볼 수 있습니다

 

https://kr.investing.com/economic-calendar/initial-jobless-claims-294

 

미국 신규 실업수당청구건수

신규 실업수당청구건수 같은 주요 경제 이벤트 및 글로벌 마켓에 미치는 그 영향력을 실시간으로 확인하세요.

kr.investing.com

 

 

📝실업률

실업률은 지난달 실업상태에 있으며 적극적으로 구직활동을 하는 총노동력의 비율을 측정합니다


https://kr.investing.com/economic-calendar/unemployment-rate-300

 

미국 실업률

실업률 같은 주요 경제 이벤트 및 글로벌 마켓에 미치는 그 영향력을 실시간으로 확인하세요.

kr.investing.com

 

 

📝 U1 ~ U6 실업률

  • U1
    • 15주 이상 실직 상태인 사람들의 비율
    • 장기 실업의 정도를 측정
  • U2
    • 일시적 실직자와 직장을 잃은 사람들의 비율
    • 최근에 일자리를 잃은 사람들의 비율
  • U3
    • 공식 실업률. 일할 의사가 있고, 지난 4주 동안 적극적으로 구직 활동을 한 사람들의 비율
    • 가장 일반적으로 인용되는 실업률 지표로, 공식적인 실업률 통계
  • U4
    • 공식 실업률(U3)에 낙담 실업자(구직을 포기한 사람들)를 포함한 비율
    • 구직 활동을 포기한 사람들까지 포함하여 실업의 범위를 넓혀 평가
  • U5
    • U4 실업률에 더해 최근에 구직을 중단한 사람들과 부분적으로 실업 상태인 사람
    • 구직을 포기한 사람들과 더불어 현재 일시적으로 실업 상태인 사람들까지 포함
  • U6
    • U5 실업률에 더해 파트타임으로 일하고 있지만 풀타임을 원하거나 필요로 하는 사람들(불완전 고용자)을 포함한 비율
    • 가장 포괄적인 실업률 지표로, 모든 형태의 실업 및 불완전 고용을 포함

 

 

  • U1: 장기 실업률 (15주 이상 실직자).
  • U2: 일시적 실업률 (직장을 잃거나 일시적 실직자).
  • U3: 공식 실업률 (일할 의사가 있고 최근 4주간 구직 활동) [가장 심각하게 보는 연준]
  • U4: U3 + 낙담 실업자.
  • U5: U4 + 최근 구직을 포기한 사람들 및 일시적 실업 상태인 사람들.
  • U6: U5 + 불완전 고용자 (파트타임이지만 풀타임을 원하는 사람들).

 

 

 

📝장단기금리역전

장단기금리가 정상일 때 = 경기가 좋을 때

  1. 경기가 좋으면 사람들은돈을 잘 빌린다
  2. 돈을 오래 빌려줄수록 이자를 많이 받아야한다

장단기금리가 역전일 때 = 경기가 안 좋을 때

  1. 경기가 안 좋으니 돈을 사람들이 잘 안빌린다
  2. 돈을 오래 빌려주는데 이자가 낮아진다

 

장단기금리역전일 때 경기침체가 일어난 경우가 많았다

 

10년-2년과 10년-3개월 비교시 마이너스 지수로 장단기금리가 역전되어있다는 걸 알 수 있다

 

 

http://yellow.kr/financeT10Y2Y.jsp#google_vignette

 

미국 장단기 금리차 - 옐로우의 세계

미국 장단기 금리차 조회, 10-Year Treasury Constant Maturity Minus 2-Year Treasury Constant Maturity

yellow.kr

https://ko.tradingeconomics.com/united-states/3-month-bill-yield

 

 

📝EPS

EPS(1주당 순이익)는 회사가 주식 1주로 얼마의 순이익을 내고 있는지를 알려줍니다

 

🔗 참고 및 출처

https://support.stockplus.com/hc/ko/articles/5059872353305-EPS%EB%9E%80-%EC%9D%98%EB%AF%B8%EC%99%80-%ED%99%9C%EC%9A%A9%EB%B2%95

반응형
반응형

📝React 이벤트 버블링

function Button({ onClick, children }) {
  return (
    <button onClick={e => {
      e.stopPropagation();
      onClick();
    }}>
      {children}
    </button>
  );
}

export default function Toolbar() {
  return (
    <div className="Toolbar" onClick={() => {
      alert('You clicked on the toolbar!');
    }}>
      <Button onClick={() => alert('Playing!')}>
        Play Movie
      </Button>
      <Button onClick={() => alert('Uploading!')}>
        Upload Image
      </Button>
    </div>
  );
}

부여된 JSX 태그 내에서만 실행되는 onScroll을 제외한 React 내의 모든 이벤트는 전파됩니다

이걸 막기 위해서는 e.stopPropagation()으로 버블링을 안 시킬 수 있습니다

 

애초에 이렇게 만드는게 이상한 듯 싶지만 Button 외를 클릭시에 어떤 동작을 하게 할 때 필요합니다

 

예제 코드

https://codesandbox.io/p/sandbox/react-dev-qqwck7?file=%2Fsrc%2FApp.js&utm_medium=sandpack

 

https://codesandbox.io/p/sandbox/react-dev-qqwck7?file=%2Fsrc%2FApp.js&utm_medium=sandpack

 

codesandbox.io

 

 

이벤트 버블링 참고내용

https://mondaymonday2.tistory.com/765

 

[JavaScript] 자바스크립트 이벤트 동작 과정 (이벤트 버블링, 이벤트 캡처, 이벤트 위임)

자바스크립트에서 이벤트가 동작되는 과정에는 두가지 방식이 있습니다. 기본적으로 이벤트 버블링으로 동작합니다. 📝이벤트 버블링 이벤트 버블링이란 하위 태그에서 이벤트가 발생할시 위

mondaymonday2.tistory.com

 

 

📝Props Drilling

보통의 경우 부모 컴포넌트에서 자식 컴포넌트로 props를 통해 정보를 전달하는데 중간에 많은 컴포넌트를 거쳐야하거나 하는경우 A의 값을 하위 B로 전달 B의 값을 하위 C로 전달... 계속적인 컴포넌트에 Props전달하는 경우를 의미합니다

 

 

📝Context를 이용해 Props Drilling 해결하기

 

 

Context를 사용하면 props를 전달하지 않아도 부모 컴포넌트에서 자식 컴포넌트에 한번에 보낼 수 있게 됩니다 간단하게 이야기하면 공통영역이 있어서 거기서 가져온다고 생각하면 됩니다

 

아래에서는 context API를 이용해 theme 즉 다크모드, 라이트모드 변경하는 예제하는 걸 보여드리겠습니다

 

다크모드인지 라이트모드인지에 대해서는 공통으로 최상단에서 관리해야하고 위에서 아래로 모든 컴포넌트에 계속 전달하기 어렵기 때문에 context API를 이용하는게 좋습니다

 

ThemeContext.js

import React, { createContext, useContext, useState } from 'react';

const ThemeContext = createContext();

export const ThemeProvider = ({ children }) => {
  const [theme, setTheme] = useState('light'); // 초기 테마는 'light'

  const toggleTheme = () => {
    setTheme((prevTheme) => (prevTheme === 'light' ? 'dark' : 'light'));
  };

  return (
    <ThemeContext.Provider value={{ theme, toggleTheme }}>
      {children}
    </ThemeContext.Provider>
  );
};

createContext로 context를 사용하기 위해 만듭니다

 

ThemeToggleButton

import React from 'react';
import { ThemeProvider, useTheme } from './ThemeContext';

const ThemeToggleButton = () => {
  const { theme, toggleTheme } = useContext(ThemeContext);

  const themeStyles = {
    backgroundColor: theme === 'light' ? '#FFF' : '#333',
    color: theme === 'light' ? '#333' : '#FFF',
  };

  return (
    <button style={themeStyles} onClick={toggleTheme}>
      Switch to {theme === 'light' ? 'Dark' : 'Light'} Mode
    </button>
  );
};

useContext로 Context에 선언된 state와 정보들을 가져오고 Toggle 버튼으로 theme값을 변경시키게 수정합니다

 

App.js

const App = () => {
  return (
    <ThemeProvider>
      <div>
        <h1>Hello, React Context API!</h1>
        <ThemeToggleButton />
      </div>
    </ThemeProvider>
  );
};

export default App;

전체 앱에 <ThemeProvider>로 감싸서 전체가 인식할 수 있게 합니다

 

 

context 사용 예시

  • context provider를 앱 최상단에 두고 시각적으로 조정이 필요한 컴포넌트에서 context를 사용할 수 있습니다.
  • 로그인한 사용자를 알아야 하는 컴포넌트가 많을 수 있습니다. Context에 놓으면 트리 어디에서나 편하게 알아낼 수 있습니다.
  • 애플리케이션이 커지면 결국 앱 상단에 수많은 state가 생기게 됩니다. 아래 멀리 떨어진 많은 컴포넌트가 그 값을 변경하고싶어할 수 있습니다.

 

context 문제점

  • 성능 이슈
    • Context API는 컴포넌트 트리의 모든 수준에서 데이터를 전달할 수 있지만, 종종 성능 문제를 일으킬 수 있습니다. Context를 사용하면 Context의 데이터가 변경될 때마다 해당 Context를 사용하는 모든 컴포넌트가 리렌더링됩니다. 이는 특히 대규모 애플리케이션에서 성능 저하를 유발할 수 있습니다.
  • 스케일링 문제
    • 작은 규모의 프로젝트에서는 효과적이지만, 애플리케이션이 커지면서 상태 관리가 복잡해질 때 Context API만으로는 관리가 어려워질 수 있습니다. 복잡한 상태 로직을 관리하고, 다양한 상태 변화를 효율적으로 처리하기 어려울 수 있습니다.
  • 구조적 한계
    • Context API는 전역 상태 관리보다는 주로 테마, 사용자 설정과 같이 고정적이고 간단한 데이터를 공유하는 데에 적합합니다. 복잡한 상태 변화와 비즈니스 로직을 포함하는 더 동적인 상태 관리에는 한계가 있습니다.

 

 

 

이러한 문제점을 해결하기 위해 다른 전역상태를 관리하는 툴을 많이 쓰는데 recoil,redux toolkit 등... 개인적으로 가장 많이 사용하는 redux toolkit을 사용하는게 좋습니다

 

반응형
반응형
export default function Signup() {
  return (
    <form onSubmit={e => {
      e.preventDefault();
      alert('Submitting!');
    }}>
      <input />
      <button>Send</button>
    </form>
  );
}

form 태그에서 onSubmit을 했을 때 화면 전체가 리로딩 되는데 이걸 e.preventDefault()를 이용해 중지시킬 수 있습니다

 

그 외 기본적으로 가지고 있는 동작을 방지하는 것에 대해서 자세히 알아보자면 아래와 같습니다 (그 외 더 많이 존재)

  1. Form 제출
    • 기본적으로 제출하면 폼 데이터가 서버로 전송되지만 폼 제출을 막아서 클라이언트 사이드에서 데이터 검증이나 다른 로직 처리가 가능합니다
  2. a태그 링크이동
    • 링크 이동을 막고 모달창 열거나 등 할 수 있습니다
  3. 마우스 오른쪽 클릭 메뉴 (컨텍스트 메뉴)
    • 오른쪽 버튼 클릭하면 컨텍스트 메뉴가 나오지만 이걸 막고 내가 원하는 컨텍스트 메뉴를 띄우거나 아예 막아버려서 컨텍스트 메뉴를 사용 못하게 할 수 있습니다
  4. 드래그 앤 드롭
    • 요즘 웹브라우저에서 이미지 등을 드래그하면 드래그 앤 드롭이 되는데 이걸 막고 다른 동작을 시킬 수 있습니다
  5. 키보드 입력 (Ctrl+S 등...)
    • 특정 키 조합 (Ctrl + S 등...) 따위를 할 때 기본 동작을 막고 사용자가 정의한 동작을 실행시킬 수 있습니다
  6. 터치 이벤트
    • 터치 기반 디바이스에서 스크롤, 스와이프와 같은 제스처는 특정 UI 요소에서 다르게 동작하도록 설정할 수 있습니다. 예를 들어, 캐러셀 슬라이드에서 스와이프로 슬라이드를 넘기는 동작을 구현할 때 기본 스크롤 동작을 막기 위해 사용할 수 있습니다
반응형
반응형

📝useState (상태 관리)

function MyButton() {
  const [count, setCount] = useState(0);

  function handleClick() {
    setCount(count + 1);
  }

  return (
    <button onClick={handleClick}>
      Clicked {count} times
    </button>
  );
}

리액트는 필요한 부분만 렌더링하기 위한 리액트만의 방식이 있습니다 useState라는 걸 이용해 값을 저장하고 그 값이 Setter로 변화시켰을 때 감지해 그 부분만 렌더링시키게 합니다


가장 많이 사용하는 것이라 필수적으로 익혀둬야합니다

 

  • 조건문, 반복문 또는 기타 중첩 함수 내부에서는 훅을 호출할 수 없습니다
  • 명명 규칙으로는 명사를 따르며 set + State변수명으로 setter 함수를 만드시면 됩니다

 

예제 코드

https://codesandbox.io/p/sandbox/react-dev-ryf69v?file=%2Fsrc%2FApp.js&utm_medium=sandpack

 

https://codesandbox.io/p/sandbox/react-dev-ryf69v?file=%2Fsrc%2FApp.js&utm_medium=sandpack

 

codesandbox.io

 

state가 서로 독립적이기 때문에 개별적으로 돌아갑니다

 

예제 코드

https://codesandbox.io/p/sandbox/react-dev-5rx42k?file=%2Fsrc%2FApp.js&utm_medium=sandpack

 

https://codesandbox.io/p/sandbox/react-dev-5rx42k?file=%2Fsrc%2FApp.js&utm_medium=sandpack

 

codesandbox.io

 

📝useState (객체, 배열) 

import { useState } from 'react';

export default function Form() {
  const [person, setPerson] = useState({
    firstName: 'Barbara',
    lastName: 'Hepworth',
    email: 'bhepworth@sculpture.com'
  });

  function handleFirstNameChange(e) {
    setPerson({
      ...person,
      firstName: e.target.value
    });
  }

  function handleLastNameChange(e) {
    setPerson({
      ...person,
      lastName: e.target.value
    });
  }

  function handleEmailChange(e) {
    setPerson({
      ...person,
      email: e.target.value
    });
  }

  return (
    <>
      <label>
        First name:
        <input
          value={person.firstName}
          onChange={handleFirstNameChange}
        />
      </label>
      <label>
        Last name:
        <input
          value={person.lastName}
          onChange={handleLastNameChange}
        />
      </label>
      <label>
        Email:
        <input
          value={person.email}
          onChange={handleEmailChange}
        />
      </label>
      <p>
        {person.firstName}{' '}
        {person.lastName}{' '}
        ({person.email})
      </p>
    </>
  );
}

state에 저장한 자바스크립트 객체와 배열은 어떤 것이라도 읽기 전용인 것처럼 다루어야 합니다

 

렌더링시 상태 값에 변화를 주려면 setState에 새로운 객체 및 배열을 할당해줘야하고 ...로 기존 데이터를 유지시키며 다른 데이터를 덮어씌워서 변화를 줄 수 있습니다

 

  비선호 (배열 변경) 선호 (새 배열 반환)
추가 push, unshift concat, [...arr] 전개 연산자
제거 pop, shift, splice filter, slice
교체 splice, arr[i] = 값 할당 map
정렬 reverse, sort 배열 복사한 이후에 처리

React에서 선호하는 방식으로 배열 함수를 사용해서 새로운 배열을 만들어서 setState에 할당해주면 됩니다

 

📝useState 동작과정

state 변화가 일어날 때 스냅샷을 만든 다음 state 변화에 대한 내용을 작성합니다 그 이후 현재 화면과 스냅샷 화면을 비교해서 해당 부분만 업데이트합니다

 

export default function Counter() {
  const [number, setNumber] = useState(0);

  return (
    <>
      <h1>{number}</h1>
      <button onClick={() => {
        setNumber(number + 1);
        setNumber(number + 1);
        setNumber(number + 1);
      }}>+3</button>
    </>
  )
}

/** 첫번째 클릭 **/
<button onClick={() => {
  setNumber(0 + 1);
  setNumber(0 + 1);
  setNumber(0 + 1);
}}>+3</button>

/** 두번째 클릭 **/
<button onClick={() => {
  setNumber(1 + 1);
  setNumber(1 + 1);
  setNumber(1 + 1);
}}>+3</button>

위코드를 실행시킬 경우 +3이 아니라 가장 마지막에 있는 변화만 적용시킵니다 그래서 1이 보이게 됩니다

 

예제 코드

https://codesandbox.io/s/ffhp6h?file=%2Fsrc%2FApp.js&utm_medium=sandpack

 

react.dev - CodeSandbox

react.dev using react, react-dom, react-scripts

codesandbox.io

 

import { useState } from 'react';

export default function Counter() {
  const [number, setNumber] = useState(0);

  return (
    <>
      <h1>{number}</h1>
      <button onClick={() => {
        setNumber(number + 5);
        setTimeout(() => {
          alert(number);
        }, 3000);
      }}>+5</button>
    </>
  )

시간의 경과가 있어도 동일하게 작동합니다

 

요약하자면 처음 클릭할 때 state는 유지되고 그 context가 있기 때문에  3초가 지나도 alert에도 0이 찍히게 되고 렌더링 한 이후에는 state가 바뀌게 되고 서로 다른 context가 존재하기 때문에 서로 간섭 안 해서 사이드이펙트가 일어나지 않습니다

 

예제 코드

https://codesandbox.io/s/sz392q?file=%2Fsrc%2FApp.js&utm_medium=sandpack

 

react.dev - CodeSandbox

react.dev using react, react-dom, react-scripts

codesandbox.io

 

 

📝같은 자리의 컴포넌트 state 보존 (state 특징)

import { useState } from 'react';

export default function App() {
  const [isFancy, setIsFancy] = useState(false);
  return (
    <div>
      {isFancy ? (
        <Counter isFancy={true} /> 
      ) : (
        <Counter isFancy={false} /> 
      )}
      <label>
        <input
          type="checkbox"
          checked={isFancy}
          onChange={e => {
            setIsFancy(e.target.checked)
          }}
        />
        Use fancy styling
      </label>
    </div>
  );
}

function Counter({ isFancy }) {
  const [score, setScore] = useState(0);
  const [hover, setHover] = useState(false);

  let className = 'counter';
  if (hover) {
    className += ' hover';
  }
  if (isFancy) {
    className += ' fancy';
  }

  return (
    <div
      className={className}
      onPointerEnter={() => setHover(true)}
      onPointerLeave={() => setHover(false)}
    >
      <h1>{score}</h1>
      <button onClick={() => setScore(score + 1)}>
        Add one
      </button>
    </div>
  );
}

여기서 삼항연산자로 true일경우 <Counter isFancy={true}/> false일 경우 <Counter isFancy={false}/>을 보여주는데 체크박스로 isFancy값을 변경시켜도 Counter에 있는 count값은 변화하지 않는데 같은 자리의 같은 컴포넌트는 state를 보존합니다

 

 

 

예제 코드

https://codesandbox.io/s/6f2zp8?file=%2Fsrc%2FApp.js&utm_medium=sandpack

 

react.dev - CodeSandbox

react.dev using react, react-dom, react-scripts

codesandbox.io

 

📝같은 자리의 컴포넌트 state 보존 안 시키기 (state 특징)

import { useState } from 'react';

export default function Scoreboard() {
  const [isPlayerA, setIsPlayerA] = useState(true);
  return (
    <div>
      {isPlayerA &&
        <Counter person="Taylor" />
      }
      {!isPlayerA &&
        <Counter person="Sarah" />
      }
      <button onClick={() => {
        setIsPlayerA(!isPlayerA);
      }}>
        Next player!
      </button>
    </div>
  );
}

function Counter({ person }) {
  const [score, setScore] = useState(0);
  const [hover, setHover] = useState(false);

  let className = 'counter';
  if (hover) {
    className += ' hover';
  }

  return (
    <div
      className={className}
      onPointerEnter={() => setHover(true)}
      onPointerLeave={() => setHover(false)}
    >
      <h1>{person}'s score: {score}</h1>
      <button onClick={() => setScore(score + 1)}>
        Add one
      </button>
    </div>
  );
}

이건 위에 코드랑 비슷해보이지만 삼항연산자로 되어있는게 아니라서 위치가 바뀌기 때문에 state가 유지가 안 됩니다

 

 

예제 코드

https://codesandbox.io/s/g9f9r8?file=%2Fsrc%2FApp.js&utm_medium=sandpack

 

react.dev - CodeSandbox

react.dev using react, react-dom, react-scripts

codesandbox.io

 

import { useState } from 'react';

export default function Scoreboard() {
  const [isPlayerA, setIsPlayerA] = useState(true);
  return (
    <div>
      {isPlayerA ? (
        <Counter key="Taylor" person="Taylor" />
      ) : (
        <Counter key="Sarah" person="Sarah" />
      )}
      <button onClick={() => {
        setIsPlayerA(!isPlayerA);
      }}>
        Next player!
      </button>
    </div>
  );
}

function Counter({ person }) {
  const [score, setScore] = useState(0);
  const [hover, setHover] = useState(false);

  let className = 'counter';
  if (hover) {
    className += ' hover';
  }

  return (
    <div
      className={className}
      onPointerEnter={() => setHover(true)}
      onPointerLeave={() => setHover(false)}
    >
      <h1>{person}'s score: {score}</h1>
      <button onClick={() => setScore(score + 1)}>
        Add one
      </button>
    </div>
  );
}

key를 주게 되면 위치로 판단하는게 아니라 key로 찾아가기 때문에 삼항연산자를 써도 state가 초기화됩니다

 

예제 코드

https://codesandbox.io/p/sandbox/react-dev-wvssxq?file=%2Fsrc%2FApp.js&utm_medium=sandpack

 

https://codesandbox.io/p/sandbox/react-dev-wvssxq?file=%2Fsrc%2FApp.js&utm_medium=sandpack

 

codesandbox.io

 

 

 

 

📝렌더링 전에 동일 state 변수 여러번 업데이트

import { useState } from 'react';

export default function Counter() {
  const [number, setNumber] = useState(0);

  return (
    <>
      <h1>{number}</h1>
      <button onClick={() => {
        setNumber(n => n + 1);
        setNumber(n => n + 15);
        setNumber(n => n + 10);
      }}>+N</button>
    </>
  )
}

흔한 사례는 아니지만 만약 동일한 Context내에서 state 변수를 여러번 업데이트 하려면 위와 같이 사용하면 됩니다

여기서 n은 변화된 값을 가지고 있는 변수라고 생각하시면 됩니다 그렇기 때문에 원래라면 10이 보여야하지만 1+15+10을 다 더한 26이 보이게 됩니다

 

📝연관된 state 그룹화 (React State 팁)

/** 변경전 **/
const [x, setX] = useState(0);
const [y, setY] = useState(0);

/** 변경후 **/
const [position, setPosition] = useState({ x: 0, y: 0 });

두 개의 state 변수가 항상 함께 변경된다면, 단일 state 변수로 통합하는 것이 좋습니다

 

📝state 중복 피하기 (React State 팁)

import { useState } from 'react';

const initialItems = [
  { title: 'pretzels', id: 0 },
  { title: 'crispy seaweed', id: 1 },
  { title: 'granola bar', id: 2 },
];

export default function Menu() {
  const [items, setItems] = useState(initialItems);
  const [selectedItem, setSelectedItem] = useState(
    items[0]
  );

  function handleItemChange(id, e) {
    setItems(items.map(item => {
      if (item.id === id) {
        return {
          ...item,
          title: e.target.value,
        };
      } else {
        return item;
      }
    }));
  }

  return (
    <>
      <h2>What's your travel snack?</h2> 
      <ul>
        {items.map((item, index) => (
          <li key={item.id}>
            <input
              value={item.title}
              onChange={e => {
                handleItemChange(item.id, e)
              }}
            />
            {' '}
            <button onClick={() => {
              setSelectedItem(item);
            }}>Choose</button>
          </li>
        ))}
      </ul>
      <p>You picked {selectedItem.title}.</p>
    </>
  );
}

현재는 선택된 항목을 selectedItem state 변수에 객체로 저장합니다. 그러나 이는 좋지 않습니다. selectedItem의 내용이 items 목록 내의 항목 중 하나와 동일한 객체입니다. 이는 항목 자체에 대한 정보가 두 곳에서 중복되는 것입니다

 

“Choose”를 클릭한  이를 편집할 경우, 입력이 업데이트되지만, 하단의 라벨에는 편집 내용이 반영되지 않습니다 

 

예제 코드

https://codesandbox.io/s/qwm2gy?file=%2Fsrc%2FApp.js&utm_medium=sandpack

 

react.dev - CodeSandbox

react.dev using react, react-dom, react-scripts

codesandbox.io

 

 

import { useState } from 'react';

const initialItems = [
  { title: 'pretzels', id: 0 },
  { title: 'crispy seaweed', id: 1 },
  { title: 'granola bar', id: 2 },
];

export default function Menu() {
  const [items, setItems] = useState(initialItems);
  const [selectedId, setSelectedId] = useState(0);

  const selectedItem = items.find(item =>
    item.id === selectedId
  );

  function handleItemChange(id, e) {
    setItems(items.map(item => {
      if (item.id === id) {
        return {
          ...item,
          title: e.target.value,
        };
      } else {
        return item;
      }
    }));
  }

  return (
    <>
      <h2>What's your travel snack?</h2>
      <ul>
        {items.map((item, index) => (
          <li key={item.id}>
            <input
              value={item.title}
              onChange={e => {
                handleItemChange(item.id, e)
              }}
            />
            {' '}
            <button onClick={() => {
              setSelectedId(item.id);
            }}>Choose</button>
          </li>
        ))}
      </ul>
      <p>You picked {selectedItem.title}.</p>
    </>
  );
}

selectedItem을 selectedItemId로 변경하고 id값으로 item을 찾으면 item이 변경되어도 똑같이 변경되게 되는 것이죠

 

 

예제 코드 (개선)

https://codesandbox.io/s/8mhwpl?file=%2Fsrc%2FApp.js&utm_medium=sandpack

 

react.dev - CodeSandbox

react.dev using react, react-dom, react-scripts

codesandbox.io

 

📝깊게 중첩된 state 피하기 (React State 팁)

export const initialTravelPlan = {
  id: 0,
  title: '(Root)',
  childPlaces: [{
    id: 1,
    title: 'Earth',
    childPlaces: [{
      id: 2,
      title: 'Africa',
      childPlaces: [{
        id: 3,
        title: 'Botswana',
        childPlaces: []
      }, {
        id: 4,
        title: 'Egypt',
        childPlaces: []
      }, {
        id: 5,
        title: 'Kenya',
        childPlaces: []
      }, {
        id: 6,
        title: 'Madagascar',
        childPlaces: []
      }, {
        id: 7,
        title: 'Morocco',
        childPlaces: []
      }, {
        id: 8,
        title: 'Nigeria',
        childPlaces: []
      }, {
        id: 9,
        title: 'South Africa',
        childPlaces: []
      }]
    }, {
      id: 10,
      title: 'Americas',
      childPlaces: [{
        id: 11,
        title: 'Argentina',
        childPlaces: []
      }, {
        id: 12,
        title: 'Brazil',
        childPlaces: []
      }, {
        id: 13,
        title: 'Barbados',
        childPlaces: []
      }, {
        id: 14,
        title: 'Canada',
        childPlaces: []
      }, {
        id: 15,
        title: 'Jamaica',
        childPlaces: []
      }, {
        id: 16,
        title: 'Mexico',
        childPlaces: []
      }, {
        id: 17,
        title: 'Trinidad and Tobago',
        childPlaces: []
      }, {
        id: 18,
        title: 'Venezuela',
        childPlaces: []
      }]
    }, {
      id: 19,
      title: 'Asia',
      childPlaces: [{
        id: 20,
        title: 'China',
        childPlaces: []
      }, {
        id: 21,
        title: 'India',
        childPlaces: []
      }, {
        id: 22,
        title: 'Singapore',
        childPlaces: []
      }, {
        id: 23,
        title: 'South Korea',
        childPlaces: []
      }, {
        id: 24,
        title: 'Thailand',
        childPlaces: []
      }, {
        id: 25,
        title: 'Vietnam',
        childPlaces: []
      }]
    }, {
      id: 26,
      title: 'Europe',
      childPlaces: [{
        id: 27,
        title: 'Croatia',
        childPlaces: [],
      }, {
        id: 28,
        title: 'France',
        childPlaces: [],
      }, {
        id: 29,
        title: 'Germany',
        childPlaces: [],
      }, {
        id: 30,
        title: 'Italy',
        childPlaces: [],
      }, {
        id: 31,
        title: 'Portugal',
        childPlaces: [],
      }, {
        id: 32,
        title: 'Spain',
        childPlaces: [],
      }, {
        id: 33,
        title: 'Turkey',
        childPlaces: [],
      }]
    }, {
      id: 34,
      title: 'Oceania',
      childPlaces: [{
        id: 35,
        title: 'Australia',
        childPlaces: [],
      }, {
        id: 36,
        title: 'Bora Bora (French Polynesia)',
        childPlaces: [],
      }, {
        id: 37,
        title: 'Easter Island (Chile)',
        childPlaces: [],
      }, {
        id: 38,
        title: 'Fiji',
        childPlaces: [],
      }, {
        id: 39,
        title: 'Hawaii (the USA)',
        childPlaces: [],
      }, {
        id: 40,
        title: 'New Zealand',
        childPlaces: [],
      }, {
        id: 41,
        title: 'Vanuatu',
        childPlaces: [],
      }]
    }]
  }, {
    id: 42,
    title: 'Moon',
    childPlaces: [{
      id: 43,
      title: 'Rheita',
      childPlaces: []
    }, {
      id: 44,
      title: 'Piccolomini',
      childPlaces: []
    }, {
      id: 45,
      title: 'Tycho',
      childPlaces: []
    }]
  }, {
    id: 46,
    title: 'Mars',
    childPlaces: [{
      id: 47,
      title: 'Corn Town',
      childPlaces: []
    }, {
      id: 48,
      title: 'Green Hill',
      childPlaces: []      
    }]
  }]
};

만일 state가 쉽게 업데이트하기에 너무 중첩되어 있다면, “평탄”하게 만드는 것을 고려하세요

 

예제 코드

https://codesandbox.io/s/vmm64f?file=%2Fsrc%2Fplaces.js&utm_medium=sandpack

 

react.dev - CodeSandbox

react.dev using react, react-dom, react-scripts

codesandbox.io

 

 

개선된 코드

export const initialTravelPlan = {
  0: {
    id: 0,
    title: '(Root)',
    childIds: [1, 42, 46],
  },
  1: {
    id: 1,
    title: 'Earth',
    childIds: [2, 10, 19, 26, 34]
  },
  2: {
    id: 2,
    title: 'Africa',
    childIds: [3, 4, 5, 6 , 7, 8, 9]
  }, 
  3: {
    id: 3,
    title: 'Botswana',
    childIds: []
  },
  4: {
    id: 4,
    title: 'Egypt',
    childIds: []
  },
  5: {
    id: 5,
    title: 'Kenya',
    childIds: []
  },
  6: {
    id: 6,
    title: 'Madagascar',
    childIds: []
  }, 
  7: {
    id: 7,
    title: 'Morocco',
    childIds: []
  },
  8: {
    id: 8,
    title: 'Nigeria',
    childIds: []
  },
  9: {
    id: 9,
    title: 'South Africa',
    childIds: []
  },
  10: {
    id: 10,
    title: 'Americas',
    childIds: [11, 12, 13, 14, 15, 16, 17, 18],   
  },
  11: {
    id: 11,
    title: 'Argentina',
    childIds: []
  },
  12: {
    id: 12,
    title: 'Brazil',
    childIds: []
  },
  13: {
    id: 13,
    title: 'Barbados',
    childIds: []
  }, 
  14: {
    id: 14,
    title: 'Canada',
    childIds: []
  },
  15: {
    id: 15,
    title: 'Jamaica',
    childIds: []
  },
  16: {
    id: 16,
    title: 'Mexico',
    childIds: []
  },
  17: {
    id: 17,
    title: 'Trinidad and Tobago',
    childIds: []
  },
  18: {
    id: 18,
    title: 'Venezuela',
    childIds: []
  },
  19: {
    id: 19,
    title: 'Asia',
    childIds: [20, 21, 22, 23, 24, 25],   
  },
  20: {
    id: 20,
    title: 'China',
    childIds: []
  },
  21: {
    id: 21,
    title: 'India',
    childIds: []
  },
  22: {
    id: 22,
    title: 'Singapore',
    childIds: []
  },
  23: {
    id: 23,
    title: 'South Korea',
    childIds: []
  },
  24: {
    id: 24,
    title: 'Thailand',
    childIds: []
  },
  25: {
    id: 25,
    title: 'Vietnam',
    childIds: []
  },
  26: {
    id: 26,
    title: 'Europe',
    childIds: [27, 28, 29, 30, 31, 32, 33],   
  },
  27: {
    id: 27,
    title: 'Croatia',
    childIds: []
  },
  28: {
    id: 28,
    title: 'France',
    childIds: []
  },
  29: {
    id: 29,
    title: 'Germany',
    childIds: []
  },
  30: {
    id: 30,
    title: 'Italy',
    childIds: []
  },
  31: {
    id: 31,
    title: 'Portugal',
    childIds: []
  },
  32: {
    id: 32,
    title: 'Spain',
    childIds: []
  },
  33: {
    id: 33,
    title: 'Turkey',
    childIds: []
  },
  34: {
    id: 34,
    title: 'Oceania',
    childIds: [35, 36, 37, 38, 39, 40, 41],   
  },
  35: {
    id: 35,
    title: 'Australia',
    childIds: []
  },
  36: {
    id: 36,
    title: 'Bora Bora (French Polynesia)',
    childIds: []
  },
  37: {
    id: 37,
    title: 'Easter Island (Chile)',
    childIds: []
  },
  38: {
    id: 38,
    title: 'Fiji',
    childIds: []
  },
  39: {
    id: 40,
    title: 'Hawaii (the USA)',
    childIds: []
  },
  40: {
    id: 40,
    title: 'New Zealand',
    childIds: []
  },
  41: {
    id: 41,
    title: 'Vanuatu',
    childIds: []
  },
  42: {
    id: 42,
    title: 'Moon',
    childIds: [43, 44, 45]
  },
  43: {
    id: 43,
    title: 'Rheita',
    childIds: []
  },
  44: {
    id: 44,
    title: 'Piccolomini',
    childIds: []
  },
  45: {
    id: 45,
    title: 'Tycho',
    childIds: []
  },
  46: {
    id: 46,
    title: 'Mars',
    childIds: [47, 48]
  },
  47: {
    id: 47,
    title: 'Corn Town',
    childIds: []
  },
  48: {
    id: 48,
    title: 'Green Hill',
    childIds: []
  }
};

 

예제 코드

https://codesandbox.io/p/sandbox/react-dev-q63dwl?file=%2Fsrc%2Fplaces.js&utm_medium=sandpack

 

https://codesandbox.io/p/sandbox/react-dev-q63dwl?file=%2Fsrc%2Fplaces.js&utm_medium=sandpack

 

codesandbox.io

 

📝Props (데이터 전달)

export default function MyApp() {
  const [count, setCount] = useState(0);

  function handleClick() {
    setCount(count + 1);
  }

  return (
    <div>
      <h1>Counters that update together</h1>
      <MyButton count={count} onClick={()=>handleClick()} />
      <MyButton count={count} onClick={handleClick} />
      {/* 잘못된 전달 <MyButton count={count} onClick={handleClick()} /> */} 
    </div>
  );
}

function MyButton({ count, onClick }) {
  return (
    <button onClick={onClick}>
      Clicked {count} times
    </button>
  );
}

부모에서 자식 컴포넌트에 값을 전달하기위해 파라미터처럼 값을 보내줘야하는데 이러한 인자값 정의를 Props라고합니

다 (Property를 보낸다라는 느낌)

 

JSX에서 작성된 Props는 JavaScript 객체의 키가 됩니다 그래서 변수명에 대시를 포함하거나 class처럼 예약어를 사용할 수 없습니다 그래서 대부분 camelCase를 사용합니다

 

React는 {} 중괄호에 있는 건 다 실행시킵니다 그렇기 때문에 함수() 이런식으로 넣는 경우 바로 동작하게 됩니다 

Props처럼 컴포넌트에 매개변수를 넣어줄 수 있는데 함수를 넘길 경우 ()라는 실행한 값이 아닌 함수의 참조값이나 익명함수를 전달해줘야합니다

 

예제 코드
https://codesandbox.io/p/sandbox/react-dev-jmpn67?file=%2Fsrc%2FApp.js&utm_medium=sandpack

 

https://codesandbox.io/p/sandbox/react-dev-jmpn67?file=%2Fsrc%2FApp.js&utm_medium=sandpack

 

codesandbox.io

 

📝Props 기본값 설정

function Avatar({ person, size = 100 }) {
  // ...
}

위 코드처럼 기본값 설정할 수 있습니다

 

📝Props 팁

function Profile({ person, size, isSepia, thickBorder }) {
  return (
    <div className="card">
      <Avatar
        person={person}
        size={size}
        isSepia={isSepia}
        thickBorder={thickBorder}
      />
    </div>
  );
}


function Profile(props) {
  return (
    <div className="card">
      <Avatar {...props} />
    </div>
  );
}

위 코드와 같이 props의 키와 값을 동일하게 설정하면 코드를 간결화할 수 있습니다

... spread 문법은 많이 사용하기 때문에 익숙해지길 바랍니다

 

export default function StoryTray({ stories }) {
  stories.push({
    id: 'create',
    label: 'Create Story'
  });

  return (
    <ul>
      {stories.map(story => (
        <li key={story.id}>
          {story.label}
        </li>
      ))}
    </ul>
  );
}

props로 받는 데이터는 그 자체를 변형시켜서는 안 됩니다 

 

📝자식을 JSX로 전달 (children)

/** HTML 방식 **/
<div>
  <img />
</div>

/** React 방식 **/
<Card>
  <Avatar />
</Card>

컴포넌트를 중첩해서 쓰고 싶을 때가 있습니다 children을 사용하면 이를 쉽게 사용할 수있습니다

 

import Avatar from './Avatar.js';

function Card({ children }) {
  return (
    <div className="card">
      {children}
    </div>
  );
}

export default function Profile() {
  return (
    <Card>
      <Avatar
        size={100}
        person={{ 
          name: 'Katsuko Saruhashi',
          imageId: 'YfeOqp2'
        }}
      />
    </Card>
  );
}

Card 컴포넌트 안에 들어가는 하위 것들을 children으로 퉁쳐서 들어갈 수 있습니다

반응형
반응형

📝컴포넌트, JSX, TSX

/** 예제 코드 **/
export default function AboutPage() {
  return (
    <>
      <h1>About</h1>
      <p>Hello there.<br />How do you do?</p>
    </>
  );
}

function Main () {
  return(
    <AboutPage/>
  );
}


/** 외부 컴포넌트 가져오기 **/
import Gallery from './Gallery.js';

export default function App() {
  return (
    <Gallery />
  );
}

React에서는 HTML을 여러 조각으로 나눠서 재활용 및 유지보수할 수 있게 만들 수 있습니다 이걸 컴포넌트라고 합니다

React에서 HTML을 리턴해주는 파일의 역할 및 확장자JSX, TSX(타입스크립트 적용시)라고 합니다

  • JSX는 HTML보다 엄격해서 같은 태그로 닫아야합니다 → 하나의 부모 태그
    • 보통 <div> 태그로 닫지만 <div> 태그로 안 닫는 경우는 <> </> 이러한 태그로라도 닫아야합니다 
  • 대문자로 시작해야합니다
  • 다른 파일에서 사용하기 위해서는 export default로 해당 함수를 내보내야합니다

 

예제 코드

https://codesandbox.io/p/sandbox/react-dev-nh2zj3?file=%2Fsrc%2FApp.js&utm_medium=sandpack

 

https://codesandbox.io/p/sandbox/react-dev-nh2zj3?file=%2Fsrc%2FApp.js&utm_medium=sandpack

 

codesandbox.io

 

📝변수 화면 노출

/** 예제 코드 **/
return (
  <h1>
    {user.name}
  </h1>
);

export default function TodoList() {
  return (
    <h1>To Do List for {formatDate(today)}</h1>
  );
}

JSX에서 HTML 코드 안에 자바스크립트 코드를 안에 넣을 수 있는데 {}안에 넣으면 됩니다

변수를 넣었으니 변수값이 출력되는 거고 데이터 format이라든가 로직이 들어갈수도 있습니다

 

📝조건부 렌더링

/** ?을 이용한 삼항연산자 조건부 렌더링 **/
<div>
  {isLoggedIn ? (
    <AdminPanel />
  ) : (
    <LoginForm />
  )}
</div>

/** null & undefined가 아닌 값이 들어있는 경우 조건부 렌더링 **/
<div>
  {isLoggedIn && <AdminPanel />}
</div>

조건부 렌더링도 가능합니다 위에서 설명한 것처럼 {} 안에 사용하면 됩니다

조건부 렌더링의 경우 더 짧게 사용하기 위해 Javascript 문법을 사용해 표현하는 경우가 많습니다

 

&&와 그 외에 논리연산자에 더 자세히 보려면 제가 쓴 글 참고 바랍니다

https://mondaymonday2.tistory.com/848

 

[JavaScript] 자바스크립트 falsy 값, 논리연산자 축약, Null 및 undefined 변수 처리 ( ||=, &&=, ?? )

📝falsy 값falsy값이란 false, null, undefined, 0, NaN, 빈 문자열('') 등의 값을 의미한다  📝||= , &&= /** || **/console.log( "" || undefined || null || "익명"); // 익명console.log( "" || "Hello" || null || "익명"); // Hellolet nu

mondaymonday2.tistory.com

 

예제 코드

https://codesandbox.io/s/zjtyvn?file=%2Fsrc%2FApp.js&utm_medium=sandpack

 

react.dev - CodeSandbox

react.dev using react, react-dom, react-scripts

codesandbox.io

 

📝배열 렌더링

const listItems = products.map(product =>
  <li key={product.id}>
    {product.title}
  </li>
);

return (
  <ul>{listItems}</ul>
);

배열로 데이터가 내려오면서 배열안에 데이터를 같은 형태의 HTML로 노출할 때 많이 사용합니다

map함수를 이용해 배열값을 렌더링 시킬 수 있습니다

 

const listItems = chemists.map(person =>
  <li>...</li> // 암시적 반환!
);

const listItems = chemists.map(person => { // 중괄호
  return <li>...</li>;
});

화살표 함수는 => 바로 뒤에 식을 반환하기 때문에 return이 필요하지 않지만 => 뒤에 {} 중괄호가 오는 경우는 return을 명시해야합니다

 

예제코드

https://codesandbox.io/s/2dmxxm?file=%2Fsrc%2FApp.js&utm_medium=sandpack

 

react.dev - CodeSandbox

react.dev using react, react-dom, react-scripts

codesandbox.io

 

📝배열 렌더링 Key 사용 이유

import { people } from './data.js';
import { getImageUrl } from './utils.js';

export default function List() {
  const listItems = people.map(person =>
    <li key={person.id}>
      <img
        src={getImageUrl(person)}
        alt={person.name}
      />
      <p>
        <b>{person.name}:</b>
        {' ' + person.profession + ' '}
        known for {person.accomplishment}
      </p>
    </li>
  );
  return (
    <article>
      <h1>Scientists</h1>
      <ul>{listItems}</ul>
    </article>
  );
}

Key는 각 컴포넌트가 어떤 배열 항목에 해당하는지 React에 알려주어 나중에 일치시킬 수 있도록 합니다

이는 배열 항목이 정렬 등으로 인해 이동하거나 삽입되거나 삭제될 수 있는 경우 중요해집니다

key를 잘 선택하면 React가 정확히 무슨 일이 일어났는지 추론하고 DOM 트리에 올바르게 업데이트 하는데 도움이 됩니다

 

데스크탑의 파일에 이름이 없다고 상상해 보세요. 대신 첫 번째 파일, 두 번째 파일 등 순서대로 파일을 참조할 것입니다. 익숙해질 수도 있지만, 파일을 삭제한다면 혼란스러워질 수도 있습니다. 두 번째 파일이 첫 번째 파일이 되고 세 번째 파일이 두 번째 파일이 되는 식으로 말이죠.

폴더의 파일 이름과 배열의 JSX key는 비슷한 용도로 사용됩니다.

이를 통해 형제 항목 간에 항목을 고유하게 식별할 수 있습니다.

잘 선택된 key는 배열 내 위치보다 더 많은 정보를 제공합니다. 재정렬로 인해 위치가 변경되더라도 key는 React가 생명주기 내내 해당 항목을 식별할 수 있게 해줍니다

 

 

Key 특징

  • key는 형제 간에 고유해야 합니다 하지만 같은 key를 다른 배열의 JSX 노드에 동일한 key를 사용해도 괜찮습니다.
  • key는 변경되어서는 안 되며 그렇게 되면 key는 목적에 어긋납니다! 렌더링 중에는 key를 생성하지 마세요.

 

Key 주의점

  • 인덱스를 key로 사용하면 종종 미묘하고 혼란스러운 버그가 발생하니 사용하지마세요
  • 마찬가지로 key={Math.random()}처럼 즉석에서 key를 생성하지 마세요. 이렇게 하면 렌더링 간에 key가 일치하지 않아 모든 컴포넌트와 DOM이 매번 다시 생성될 수 있습니다. 속도가 느려질 뿐만 아니라 리스트 항목 내부의 모든 사용자의 입력도 손실됩니다. 대신 데이터 기반의 안정적인 ID를 사용하세요

 

📝이벤트 핸들링

function MyButton() {
  function handleClick() {
    alert('You clicked me!');
  }

  return (
    <button onClick={handleClick}>
      Click me
    </button>
  );
}

React의 경우 함수의 값을 호출하는게 아닌 함수의 주소값을 전달하는 것입니다 → React에서 정한 문법이기 때문에 따라야합니다

 

📝HTML To JSX

아래 사이트에서 HTML을 JSX형식으로 변환시킬 수 있습니다

 

https://transform.tools/html-to-jsx

 

HTML to JSX

to TypeScript Declaration to TypeScript Declaration

transform.tools

 

반응형
반응형

📝SCons

오픈 소스 소프트웨어 빌드 도구로 Python으로 작성되었으며, Python 스크립트를 사용해 빌드 파일을 정의합니다. 즉, 빌드 스크립트를 작성할 때 Python의 모든 기능을 사용할 수 있다는 뜻입니다. (C/C++, Python에서 자주 사용된다고 한다)

 

📝PL/SQL (Procedural Language/Structured Query Language)

CREATE OR REPLACE PROCEDURE UpdateSalary (emp_id IN NUMBER, new_salary IN NUMBER) IS
BEGIN
  UPDATE employees
  SET salary = new_salary
  WHERE employee_id = emp_id;
END;

SQL의 기능에 더해, 조건문(IF, ELSE), 반복문(LOOP, WHILE), 변수 선언, 예외 처리 등의 절차적 제어 구조를 추가로 제공합니다. 이를 통해 복잡한 논리나 데이터 처리 작업을 보다 효율적으로 수행할 수 있습니다. PS라고도 부르는데 PS로만 구성되어있는 백엔드의 경우는 유지보수가 어렵습니다. → 추천하지 않고 적재적소로 활용 해야함

 

📝Direct3D

  • Direct3D는 마이크로소프트가 개발한 3D 그래픽 API로, 주로 윈도우 운영 체제에서 사용됩니다.
  • 이는 게임 개발과 실시간 3D 애플리케이션을 위한 고성능 그래픽 및 비디오 처리를 목표로 합니다.
  • DirectX의 일부로 통합되어 있으며, Xbox 게임 콘솔에도 사용됩니다.

📝Vulkan

  • Vulkan은 크로스 플랫폼 3D 그래픽 API로, OpenGL의 후속 제품으로 개발되었습니다.
  • 이는 고성능 및 고수준의 하드웨어 제어를 제공하여 개발자가 GPU(그래픽 처리 장치)를 더 효과적으로 활용할 수 있게 돕습니다.
  • Vulkan은 다양한 플랫폼(윈도우, 리눅스, 안드로이드 등)에서 사용할 수 있으며, 특히 게임과 같은 리소스를 많이 요구하는 애플리케이션에 적합합니다.

📝OpenGL

  • OpenGL은 널리 사용되는 크로스 플랫폼 3D 그래픽 API입니다.
  • 이는 1992년에 처음 출시되어 비디오 게임, CAD(컴퓨터 지원 설계), 가상 현실 등 다양한 분야에서 사용되었습니다.
  • OpenGL은 고수준의 추상화를 제공하여 다양한 하드웨어와 운영 체제에서의 호환성을 유지합니다.

 

📝 DOD

데이터 지향 디자인 (Data-Oriented Design, DOD)은 데이터의 구조와 효율적인 데이터 처리에 중점을 두는 프로그래밍 패러다임입니다. 이 방식은 특히 게임 개발과 같은 성능이 중요한 응용 프로그램에서 유용합니다. DOD는 데이터를 메모리에 연속적으로 배치하여 CPU 캐시 활용을 최적화하고, 데이터 처리를 병렬화하기 쉽게 만듭니다

 

전통적 객체지향 설계

class Entity {
public:
    float x, y; // 위치
    float vx, vy; // 속도

    void update(float dt) {
        x += vx * dt;
        y += vy * dt;
    }
};

int main() {
    std::vector<Entity> entities(1000);
    float dt = 0.016; // 가정: 60 FPS에 해당하는 시간 간격

    for (auto& e : entities) {
        e.update(dt);
    }
}

 

 

데이터 지향 설계

struct Position {
    std::vector<float> x, y;
};

struct Velocity {
    std::vector<float> vx, vy;
};

class EntityManager {
public:
    Position position;
    Velocity velocity;

    void update(float dt) {
        for (size_t i = 0; i < position.x.size(); ++i) {
            position.x[i] += velocity.vx[i] * dt;
            position.y[i] += velocity.vy[i] * dt;
        }
    }
};

int main() {
    EntityManager manager;
    manager.position.x.resize(1000);
    manager.position.y.resize(1000);
    manager.velocity.vx.resize(1000);
    manager.velocity.vy.resize(1000);
    float dt = 0.016; // 가정: 60 FPS에 해당하는 시간 간격

    manager.update(dt);
}

 

 

📝BI (Brand Identity)

특정 브랜드의 개성과 정체성을 시각적, 상징적 요소로 표현하는 것을 의미합니다. 브랜드가 어떤 가치를 지향하는지, 소비자들에게 어떻게 인식되기를 원하는지를 보여주는 시각적, 감정적 요소의 집합체입니다.

 

  • 스타벅스
    • 녹색과 인어 로고는 커피와 편안한 라이프스타일을 상징.
  • 나이키(Nike)
    • 로고인 스우시(swoosh)는 스피드와 역동성을 시각적으로 표현.

 

📝CI (Company Identity)

기업 자체의 정체성을 나타내는 시각적, 상징적 요소들을 말합니다. 기업이 갖고 있는 철학, 미션, 비전과 같은 근본적인 가치를 표현하는 방법이며, BI와 달리 기업 전체를 대상으로 한다는 점에서 차이가 있습니다.

 

  • 삼성
    • 파란색 로고와 ‘Samsung’을 사용하여 세계적인 기술 혁신 기업으로의 이미지를 구축.

 

📝JIT(Just-In-Time), 

프로그램 실행 시 실행 중에 필요한 부분만 즉시 컴파일하는 방식입니다. 한번 변환된 코드는 캐시되어, 같은 부분이 다시 호출될 때는 재컴파일 없이 빠르게 실행됩니다. JIT 컴파일은 프로그램이 실행되는 동안 동적으로 이루어지며, 성능 최적화를 위해 실행 시간에 따라 코드의 특정 부분을 최적화할 수 있습니다.

 

💗장점

  • 초기 실행 속도가 빠름
    • 필요한 부분만 실행 즉시 컴파일하므로 프로그램을 빨리 시작할 수 있습니다.

⚠️단점

  • 초기 실행 속도가 느려질 수 있음
    • 실행 중간에 컴파일 작업이 추가되므로 일부 작업에서 오버헤드가 발생할 수 있습니다.

 

📝 AOT(Ahead-Of-Time)

실행하기 전에 미리 기계어로 변환하여 실행하는 방식입니다. JIT와는 반대로, 컴파일 과정이 실행 전에 완료됩니다. 정적인 데이터에 처리하기 좋습니다.

 

💗장점

  • 코드가 미리 컴파일되어 있어 메모리 효율성이 높아질 수 있습니다.
  • 실행 전에 모든 컴파일이 완료되기 때문에, 실행 시간 동안 성능이 매우 빠릅니다.
  • 런타임전에 버그가 있으면 잡아낼 수 있습니다.

⚠️단점

  • 컴파일된 코드는 실행 환경의 변화에 적응하지 못하기 때문에 JIT처럼 동적인 최적화는 어렵습니다.

 

📝 HashCode

객체를 고유하게 식별하기 위해 사용하는 숫자 값을 의미합니다. 주소값이 아닌 실제 객체의 값을 의미합니다.

 

 

 

 

반응형
반응형

📝MVC

MVC패턴은 Model + View + Controller를 합친 용어입니다

동작과정으로 Controller로 (url)요청이 들어오면 Model을 이용해 데이터를 가져오고 수정해서 Controller로 보내고 해당 데이터로 View를 업데이트합니다.

 

대표적으로 Spring MVC가 있습니다. 참고로 그림이 이해가 안 되는 건 Model하고 View 결합이 없을텐데 왜 결합이 있는 것처럼 표현된 건지입니다.

 

  • Model
    • 데이터와 비즈니스 로직을 담는 공간입니다
  • View
    • 사용자에게 제공하는 UI 부분입니다 (JSP, Thymeleaf)
  • Controller
    • 들어온 데이터나 보내줄 데이터에 대한 로직처리하는 부분입니다

 

💗장점

  • 역할이 잘 분리되어 있어서 협업에 유리하고 테스트 및 유지보수(분리가 잘 되어있어서)가 쉽습니다.

 

⚠️단점

  • Controller가 여러개의 Model을 가지게 되고 그에 따라 연결된 View도 많아지기 때문에 복잡하다
    • DDD나 도메인으로 폴더구조를 잘 나누면 된다고 생각한다.

 

추후 Spring의 경우는 MVC에서 Model의 로직을 Service로 따로 분리했습니다. Model은 DTO, Entity가 이에 해당합니다. MVVM이 최신임에도 바뀌지 않는 이유는 이게 Spring 웹 프레임웨크에 가장 적합한 형태이기 때문입니다.

 

  • 사용 프레임워크
    • Ruby On Rails
    • Django
    • Spring
    • Express.js

 

// Controller
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;

@Controller
public class GreetingController {
    
    @GetMapping("/greeting")
    public String greeting(@RequestParam(name="name", required=false, defaultValue="World") String name, Model model) {
        model.addAttribute("name", name);
        return "greeting";  // 뷰 이름 반환
    }
}

 

<!-- greeting.jsp -->
<html>
<body>
    <h1>Hello, ${name}!</h1>
</body>
</html>

 

 

📝MVP

사용자가 View에서 행동을 하면 Presenter에게 요청하고 Presenter가 Model을 이용해 데이터를 받아오고 수정해서 View에게 제공합니다 MVC랑 유사합니다만 View 하나당 1개의 Presenter를 가지고 있습니다.

 

  • Model
    • 데이터 관리 및 비즈니스로직 처리
  • View
    • 사용자에게 제공하는 UI 부분입니다. 
  • Presenter
    • Model과 View 사이의 상호작용을 조정합니다. View로부터 입력을 받아 Model을 업데이트하고, Model의 상태 변경에 따라 View를 업데이트합니다.

 

💗장점

  • MVC랑 동일하고 Presenter랑 View 1:1로 관리하기 때문에 더 유지보수에 용이해보입니다.

 

  • 사용 프레임워크
    • GWT
    • Backbone.js
    • WinForms
    • Vaadin

 

HTML

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>MVP Example</title>
</head>
<body>
    <h1>MVP Example</h1>
    <div id="data-display">Click the button to load data</div>
    <button id="load-data-btn">Load Data</button>

    <script src="app.js"></script>
</body>
</html>

 

Javascript

// Model
class DataModel {
    constructor() {
        this.data = null;
    }

    // 비동기로 데이터를 받아오는 메소드
    fetchData() {
        return new Promise((resolve, reject) => {
            setTimeout(() => {
                this.data = { message: "Hello, MVP Pattern!" };
                resolve(this.data);
            }, 1000);  // 1초 후에 데이터 반환 (모의 비동기 처리)
        });
    }

    getData() {
        return this.data;
    }
}

// Presenter
class DataPresenter {
    constructor(view, model) {
        this.view = view;
        this.model = model;

        this.view.bindLoadData(this.handleLoadData.bind(this));
    }

    async handleLoadData() {
        try {
            const data = await this.model.fetchData();
            this.view.displayData(data.message);
        } catch (error) {
            this.view.displayError('Failed to load data');
        }
    }
}

// View
class DataView {
    constructor() {
        this.dataDisplay = document.getElementById('data-display');
        this.loadDataBtn = document.getElementById('load-data-btn');
    }

    bindLoadData(handler) {
        this.loadDataBtn.addEventListener('click', handler);
    }

    displayData(data) {
        this.dataDisplay.textContent = data;
    }

    displayError(error) {
        this.dataDisplay.textContent = error;
    }
}

// 초기화 코드
document.addEventListener("DOMContentLoaded", () => {
    const model = new DataModel();
    const view = new DataView();
    const presenter = new DataPresenter(view, model);
});

MVP 패턴은 데스크톱 애플리케이션을 위해 개발되었기 때문에 서버 Presenter랑 클라이언트 Presenter랑 나뉘는 형태로 현재 HTML랑 JS로 설명하기 이상할 수 있지만 가장 많이 접해봤을 웹측면에서 설명했습니다. 해당 패턴을 써보진 못해서 말만 들어서는 뭐가 발전한 거에 대해서 정확히는 잘 모르겠습니다

 

 

📝MVVM

MVP를 발전시킨 패턴으로 데이터 바인딩을 이용해 뷰와 모델사이의 결합도를 더욱 낮췄습니다 현재는 Angular, Vue.js등 다양한 프론트엔드 프레임워크에서도 채용하고 있습니다

 

💗장점

  • ViewModel에 비즈니스 로직이 집중되어 유지보수에 용이합니다.
  • ViewModel이 뷰의 상태를 관리하기 때문에, 상태 유지가 필요한 복잡한 UI의 경우에 유리합니다.

 

  • Model
    • 비즈니스 로직과 데이터를 관리합니다. 여기에서 로직이란 DB접근하던가 API통신 또는 계산 데이터처리등과 같은 로직이 해당합니다.
  • View
    • 사용자에게 제공하는 UI 부분입니다.
  • ViewModel
    • View와 Model의 중개자역할을 하며 View로부터 요청이 들어오면 Model로 처리후 필터링해 View에게 제공합니다. UI 관련 로직과 데이터를 관리합니다. 여기에서 로직이란 Model에서 데이터를 가져와 UI에 맞는 형태로 변환하거나 필터링 또는 UI 상태(로딩, 오류메시지)를 관리하고 유지하는 로직이 들어갑니다. 사용자가 버튼을 클릭하거나 입력하는 등에 대한 UI 이벤트 처리가 이에 해당합니다.
    • View와 1:N으로 연결되어서 중복을 제거하고 다른 곳에서 사용할 수 있다 → 개인적으로 DDD처럼 각각 하나씩 대응하는게 나은 거 같다 이거는 공통을 제대로 잘 뽑지 않는 이상은 의미가 없어보임 물론 MVP에서 아예 안 되는 내용이면 MVVM의 장점이라고 할수도 있을 것 같다.

 

  • 사용 프레임워크
    • Android
    • iOS
    • Flutter

Flutter 내용 추가 필요

 

📝결론

프레임워크가 그 패턴을 사용하는 건 그걸 의도하고 만든 것이기 때문에 따라가면 좋고 그걸 보완할 좋은 방안이 있으면 적용시키면 됩니다. 딱딱한 사고는 안 하는게 좋은 거 같네요 MVC의 경우도 Service 레이어가 생겨나는 등 변화가 있었으니... 그리고 그 프레임워크가 추구하는 방향대로 해야한다. 왜냐하면 그에 맞게 라이브러리가 만들어진 게 많기 때문이다. 이념에 맞지 않아 개발에 고생할 수 있음

 

📝단방향 데이터 바인딩

모델에서 뷰로 보내는 데이터의 흐름이 자동처리 되어 Model이 변경되면 View가 변경되지만 그 반대는 적용되지 않습니다 단방향 데이터 바인딩 적용한 건 React가 있다고 합니다

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>React One-way Data Binding</title>
    <script src="https://unpkg.com/react@17/umd/react.development.js"></script>
    <script src="https://unpkg.com/react-dom@17/umd/react-dom.development.js"></script>
    <script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
</head>
<body>
    <div id="root"></div>
    <script type="text/babel">
        class App extends React.Component {
            constructor(props) {
                super(props);
                this.state = { name: "World" };
            }

            handleChange = (event) => {
                this.setState({ name: event.target.value });
            };

            render() {
                return (
                    <div>
                        <input 
                            type="text" 
                            value={this.state.name} 
                            onChange={this.handleChange}
                        />
                        <p>Hello, {this.state.name}!</p>
                    </div>
                );
            }
        }

        ReactDOM.render(<App />, document.getElementById('root'));
    </script>
</body>
</html>

React의 공식 예제를 살펴보면 State로 상태를 관리하며 setState로 상태에 변화를 감지해 부분렌더링하게 되는데 onChange에 접합시켜서 input에 변화가 있을 때 input 상태값을 변화시키는 즉, HTML에서의 수정이 JS로 이어지고 JS의 수정 즉, setState로 인한 수정도 HTML에 반영되기 때문에 양방향 데이터 바인딩처럼 동작합니다

하지만 진짜 양방향의 경우 이러한 작업이 자동처럼 처리 되어 코드가 줄어들고 컴포넌트간의 데이터 전달시 props로 하위 컴포넌트로 보낼 수 있지만 상위로 보낼 수 없다는 점에서 단방향이라고 부르는 것 같네요

 

 

📝양방향 데이터 바인딩

Model을 수정시 View에 적용되며 View 수정시에도 Model에 적용되어 동기화된 상태를 유지시킵니다 이를 활용한 기술은 Angular, Vue.js가 존재합니다

 

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Angular Two-way Data Binding</title>
    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.8.2/angular.min.js"></script>
</head>
<body ng-app="myApp" ng-controller="myCtrl">
    <input type="text" ng-model="name">
    <p>Hello, {{name}}!</p>

    <script>
        var app = angular.module('myApp', []);
        app.controller('myCtrl', function($scope) {
            $scope.name = "World";
        });
    </script>
</body>
</html>

Angular의 예제를 보면 React와 다르게 간결한 코드로 양방향으로 데이터 바인딩이 가능합니다

 

📝Back-End, Front-End

요즘은 Front-End랑 Back-End로 나누어서 작업하기 때문에 역할이 잘 분리되어있습니다 물론 Front-End쪽에서는 MVVM이고 BackEnd에서는 View를 제거한 API만 제공하는 Model과 Controller만 사용하는 형태 등 이런식으로 사용하게 됩니다

 

 

🔗 참고 및 출처

https://beomy.tistory.com/43

반응형
반응형

📝리액트란

리액트는 Facebook에서 만든 Javascript 라이브러리핵심 요소가상 DOM으로 인한 빠른 렌더링 기술을 가진다

 

📝리액트 장점

  • 가상 돔을 이용한 빠른 렌더링
    • 가상돔을 이용해 필요한 부분만 렌더링해 속도의 최적화가 가능합니다
  • 클라이언트 사이드 렌더링
    • 클라이언트 측에서 렌더링하기 때문에 서버에 부담이 없어집니다
  • 컴포넌트 재활용
    • 클래스를 생성하고 객체를 만들어서 다양한 곳에 사용하는 것과 동일합니다 
    • 개인적인 의견 → 물론 사용해보니 여러명에서 개발할 때 공통 컴포넌트 자체를 만들기는 쉽지 않아보입니다 다양한 상황에는 다양한 조건들이 들어가는데 어떤 건 살짝만 다른데 코드가 더 들어가면서 코드가 덕지덕지 많아지며 점점 복잡해지니 많은 경험과 리팩토링도하면서 어떤 걸 공통으로 만들어야할지에 대한 개념을 익혀야합니다
  • React Native (크로스 플랫폼 개발)
    • React 문법을 익혀두면 React Native로 크로스 플랫폼 개발이 가능해 iOS, AOS 개발이 가능합니다
    • 개인적인 의견 →  현재 React Native의 버전이 아직도 1버전이 안 된 거보면 매우 불안정한 상태이고 공식적인 라이브러리도 따로 제공하지 않는 걸로 압니다 이 부분은 남이 만든 걸 가져다 쓰는데 업데이트가 주기적으로 이루어지지 않으면 운영하다 버그가 날 가능성이 높아보입니다
      현재 React도 비슷한 형태이지만 앱개발엔 많은 기술들이 들어가는데 React Native에서 기본적으로 제공하는 게 많이 없다면 npm에 의존할 수 밖에 없을 것 가텐요

 

📝리액트 단점

  • 러닝커브가 크다
    • 상태관리와 렌더링에 대한 개념이 어렵고 새롭기 때문에 기존 HTML과 Javascript로 개발하는 것과 다른 점이 있어서 난해할 수 있다
  • SEO 적용이 힘들다
    • 일반적으로 Server에서 그려져서 오면 검색엔진 봇이 내용을 읽어서 검색시 노출되게 할 수 있는데 React의 경우 Client Side Rendering이 주요 기술이라 Client가 제공해주는 js내용을 다운 받아서 그리기 때문에 검색엔진 봇이 들어왔을 때 아무 내용이 없어서 검색단어들을 가져갈 수 없는 것이죠 현재는 React에서도 Server Side를 지원하고 SEO 최적화를 위한 기술들을 제공하기 때문에 큰 문제가 되진 않아보입니다
  • 초기 로드시간이 느리다
    • CSR 방식을 이용하면 모든 스크립트와 리소스가 다운로드 될 때까지 기다려야 하기 때문에 첫 페이지 로드가 느릴 수 있습니다

 

📝리액트 동작과정 (Virtual Dom)

일반적으로 웹 브라우저의 동작은 웹 브라우저가 웹사이트의 텍스트 문서를 읽어서 DOM(Document Object Model)이라는 트리 구조로 바꾸어 사용자에게 보여주게 되는데, 웹 개발자들은 사용자의 반응에 따라 이 DOM 트리를 변경하여 웹사이트의 내용을 갱신합니다 (실제로 jQuery나 Vanila를 이용해 수정하게끔 이벤트를 만들어서 테스트하면 최상위 body의 값이 깜빡거리면서 전체를 렌더링하는 걸 확인할 수 있습니다) 하지만 매번 작은 변화가 있을 때마다 전체 화면을 새로 그리는 것은 성능에 좋지 않습니다

 

React는 이 문제를 해결하기 위해 Virtual DOM을 도입합니다 

Virtual Dom은 위 그림처럼 어느 부분이 변경 되어있는지 정확히 파악이 가능하기 때문에 변화를 주고 싶은 부분만 Virtual DOM에서 수정하게 됩니다

 

또한 DOM을 직접 조작하는 건 low-level이라 까다롭고 안정성이 떨어집니다 특히 규모가 커지면 엄청 많은 코드를 적어야할지도 모릅니다 그래서 돔으로 직접 조작하는 jQuery와 같은 라이브러리는 legacy 취급을 받습니다

 

📝Angular(앵귤러) vs Vue.js vs React

Angular, React, Vue 전부 비슷한 계열의 CSR이며 필요한 부분만 렌더링하는 기술들이 들어가있습니다

 

  • Angular
    • 구글에서 만든 프레임워크로서 구글에서 만들었지만 2년째 업데이트가 안 되고 있네요 구글에서는 자주 가져다 버리는 프로젝트들이 많습니다 어떤 기술을 택할 때 중요한 부분이니 고려 바랍니다
  • Vue
    • 1인 개발자가 만든 프레임워크인데 현재 다운로드수도 Angular에 비해 많고 React에 비해서 쉽다고 합니다

 

개인적으로 가장 많이 쓰면서 안정화된 버전이 나오고 최근에 업데이트되고 있는 기술을 쓰는게 좋습니다 고로 React를 사용하는게 좋다고 생각해요 물론 우리나라 취업시장을 고려하긴 해야합니다

 

🔗 참고 및 출처
https://velog.io/@juno7803/React%EA%B0%80-%ED%83%9C%EC%96%B4%EB%82%9C-%EB%B0%B0%EA%B2%BD

[React] React란? 동작원리는 어떻게 될까? (tistory.com)

https://modulabs.co.kr/blog/react-library/
https://npmtrends.com/angular-vs-react-vs-vue

반응형