(본 글은 Velopert님의 https://react.vlpt.us/ 를 정리한 내용입니다.)
- 기존 자바스크립트를 사용해서 동적인 처리를 하기 위해서는 DOM을 직접 건드려야 했다.
(이러한 방식은 규모가 커지면 관리하기 힘들어짐)- 그래서 AngularJS와 같은 프레임 워크가 등장한다. 이 프레임 워크의 원리는 특정 값이 바뀌면 특정 DOM의 속성을 바꾸어서 업데이트를 해주는 방식
- 하지만, 리액트는 Virtual DOM을 이용해서 업데이트 된 곳만 파악한 뒤,
전부 다 날리고 새로 만들어서 보여주는 방식
function Hello({ color, name }) { return <div style={{ color }}>안녕하세요 {name}</div> } Hello.defaultProps = { name: '이름없음' }
: 개발자가 만든 컴포넌트 안에 컴포넌트를 넣기 위해서는 props.children을 사용해야 한다.
- Wrapper컴포넌트에 Hello라는 컴포넌트를 넣는 예제
(App.js)
function App() { return ( <Wrapper> <Hello name="react" color="red"/> <Hello color="pink"/> </Wrapper> ); }
(Wrapper.js)
function Wrapper({ children }) { // props.children을 비구조화 할당으로 받는 부분 const style = { border: '2px solid black', padding: '16px', }; return ( <div style={style}> {children} // 출력 </div> ) }
조건부 렌더링
1) 삼항 연산자 사용
<div> { isSpecial ? <b>*</b> : null } </div>
2) && 사용 (권장 방법)
<div> {isSpecial && <b>*</b>} </div>
: onChange()와 이벤트 객체(e)를 통해서 설정
function InputSample() { const [text, setText] = useState(''); const onChange = (e) => { setText(e.target.value); }; const onReset = () => { setText(''); }; return ( <div> <input onChange={onChange} value={text} /> <div> <b>값: {text}</b> </div> </div> ); }
: 여러개의 input값을 처리할 때 하나 씩 변수를 useState()로 해도 괜찮지만,
여러 변수를 받는 Inputs를 통해서 하나의 onChange로 사용할 수 있다.
function InputSample() { const [inputs, setInputs] = useState({ name: '', nickname: '' }); const { name, nickname } = inputs; // 비구조화 할당을 통해 값 추출 const onChange = (e) => { const { value, name } = e.target; // 우선 e.target 에서 name 과 value 를 추출 setInputs({ ...inputs, // 기존의 input 객체를 복사한 뒤 [name]: value // name 키를 가진 값을 value 로 설정 }); }; return ( <div> <input name="name" placeholder="이름" onChange={onChange} value={name} /> <input name="nickname" placeholder="닉네임" onChange={onChange} value={nickname}/> <div> <b>값: </b> {name} ({nickname}) </div> </div> ); }
- input 객체의 내부 값에 대한 접근 방법
inputs[name] = value;
: JS에서 특정 DOM에 접근하기 위해 geElementById, querySelector을 사용했다.
리액트에서는 ref라는 것을 사용해서 특정 DOM에 접근한다.
1) ref 변수 선언
const nameInput = useRef();
2) 접근 할 DOM에 ref 선언
<input name="name" placeholder="이름" onChange={onChange} value={name} ref={nameInput} // ref 선언 />
3) ref 사용
nameInput.current.focus(); // focus말고도 다른 함수도 존재!
1) key가 없을 때
: key가 없을 때 삽입을 하게 되면 중간에 들어가는 것이 아니라 하나 씩 밀리면서 들어간 것처럼 보이게 된다 (비효율적)
2) key가 있을 때
: key가 있다면 각 엘리먼트를 식별하여 효율적으로 연산이 이루어진다.(효율적)
: state값이 변경되면 re-render 되기 때문에 re-render이 필요 없는 변수를 사용할 때에 useRef를 이용한다.
1) 선언
const nextId = useRef(4); // 들어가는 값은 초기화 값
2) 사용
nextId.current += 1;
: React에서는 효율적인 렌더링을 하기 위한 React.memo사용을 위해 state값은 불변성을 지켜야 한다. 따라서 배열의 원본 값에 추가하는 concat이나 ...(spread 연산자)가 필요하다.
1) spread 연산자 사용(...)
const user = { id: nextId.current, username, email }; setUsers([...users, user]); // users라는 state에 입력된 값을 추가하는 코드이다. // spread 연산자 ...를 사용해서 원본 값에 추가하여 state를 변경하였다.
2) concat 사용
const user = { id: nextId.current, username, email }; setUsers(users.concat(user)); // users라는 state에 입력된 값을 추가하는 코드이다. // .concat(추가할 값) 을 통해서 원본 값을 유지한 채 추가하였다.
: id값을 넘겨 받은 뒤 .filter()를 사용해서 하면 편하다.
const onRemove = id => { // user.id 가 파라미터로 일치하지 않는 원소만 추출해서 새로운 배열을 만듬 // = user.id 가 id 인 것을 제거함 setUsers(users.filter(user => user.id !== id)); };
: 토글 버튼을 클릭하여 속성을 변경시킬 수 있다.
const onToggle = id => { setUsers( users.map(user => user.id === id ? { ...user, active: !user.active } : user ) ); };
- 특정 값에 따라 style을 다르게 적용 가능
<b style={{ cursor: 'pointer', color: user.active ? 'green' : 'black' }} {user.username} </b>