Main Course 주특기 2강 - React

주특기 2강!

  1. 컴포넌트의 state를 관리할 수 있다.
  2. 컴포넌트의 라이프 사이클을 이해한다.
  3. 오픈소스 패키지를 찾아서 설치할 수 있다.
  4. event listener를 구독할 수 있다.
  5. React hook 중 useState(), useEffect()를 사용할 수 있다.

scss

// Nesting이 가능하다.
// div 아래에 p, img 태그 스타일을 줄 때, 각각 다른 블럭을 만들어 쓸 필요가 없어요!
// 축약형으로 묶을 수 있어요. → xxx-yyy 식일 때, 앞에 xxx가 같은 친구끼리 묶어 쓸 수 있어요!
div {
	p {
		color: #888888;
		font: {
		    family:sans-serif; 
		    size: 14px;
		}
	}
	
	img {
	    width: 400px;
	}
}

// 상위 요소 이어쓰기는 "&"로! 클래스명 등, 글자도 이어쓸 수 있어요.
div {
  background-color: green
  &:hover { background-color: blue }
}
.div {
  background-color: green
 &_blue { background-color: blue }
}

// 문자열을 치환할 수 있습니다! (즉, 변수를 쓸 수 있어요!)
$defaultSize: 20px;
$className: blue;

p{
	font-size: #{$defaultSize};
	&.#{$className} {color: #{$className}}
}

styled-components

yarn add styled-components

패키지 설치하기

function App() {
  return (
    <div className="App">
      {/* props로 bgColor를 줘볼까요! */}
      <MyStyled bgColor를={"red"}>hello React!</MyStyled>
    </div>
  );
}

// scss처럼 자기 자신을 지칭할 때 &를 쓸 수 있습니다!
// props 주는 방법! 이제 알고 있죠?
// 백틱을 사용함
const MyStyled = styled.div` 
  width: 50vw;
  min-height: 150px;
  padding: 10px;
  border-radius: 15px;
  color: #fff;
  &:hover{
    background-color: #ddd;
  }
  background-color: ${(props) => (props.bgColor ? "red" : "purple")};
`;

Life Cycle

  • 컴포넌트는 생성되고 → 수정(업데이트)되고 → 사라집니다.
  • 생성은 처음으로 컴포넌트를 불러오는 단계입니다.
  • 수정(업데이트)는 사용자의 행동(클릭, 데이터 입력 등)으로 데이터가 바뀌거나, 부모 컴포넌트가 렌더링할 때 업데이트 됩니다. 아래의 경우죠!
    • props가 바뀔 때
    • state가 바뀔 때
    • 부모 컴포넌트가 업데이트 되었을 때(=리렌더링했을 때)
    • 또는, 강제로 업데이트 했을 경우! (forceUpdate()를 통해 강제로 컴포넌트를 업데이트할 수 있습니다.)
  • 제거는 페이지를 이동하거나, 사용자의 행동(삭제 버튼 클릭 등)으로 인해 컴포넌트가 화면에서 사라지는 단계입니다.
  1. constructor()
    생성자 함수라고도 부릅니다. 컴포넌트가 생성되면 가장 처음 호출되는 친구죠!

  2. render()
    컴포넌트의 모양을 정의하는 친구입니다!
    여기에서도 state, props에 접근해서 데이터를 보여줄 수 있어요.
    리액트 요소를 return에 넣어 반환해줬던 거 기억하시죠?
    render() 안에 들어갈 내용은 컴포넌트의 모양에만 관여하는 것이 가장 좋습니다.
    즉, state나, props를 건드려 데이터를 수정하려고 하면 안됩니다!

  3. componentDidMount()
    컴포넌트가 화면에 나타나는 것을 마운트(Mount)한다고 표현합니다. didMount()는 마운트가 완료 되었다는 소리겠죠?
    이 함수는 첫번째 렌더링을 마친 후에만 딱 한 번 실행됩니다. 컴포넌트가 리렌더링할 때는 실행되지 않아요.
    보통은 이 안에서 ajax 요청, 이벤트 등록, 함수 호출 등 작업을 처리합니다.
    또, 이미 가상돔이 실제돔으로 올라간 후니까 DOM 관련 처리를 해도 됩니다!

  4. componentDidUpdate(prevProps, prevState, snapshot)
    DidMount()가 첫 렌더링 후에 호출 되는 함수라면, DidUpdate()는 리렌더링을 완료한 후 실행되는 함수입니다.
    이 함수에 중요한 파라미터가 2개 있는데, prevProps와 prevState입니다. 각각 업데이트 되기 전 props, state예요. 이전 데이터와 비교할 일이 있다면 가져다 쓰도록 합시다.
    DidUpdate()가 실행될 때도 가상돔이 실제돔으로 올라간 후니까 DOM 관련 처리를 해도 됩니다!

  5. componentWillUnmount()
    컴포넌트가 DOM에서 제거 될 때 실행하는 함수입니다.
    만약 우리가 스크롤 위치를 추적 중이거나, 어떤 이벤트 리스너를 등록했다면 여기에서 꼭꼭 해제를 해줘야 합니다.
    컴포넌트 없이 이벤트만 남겨둘 순 없잖아요!

Ref

특정 요소에 접근하는 방법으로 사용됨.
클래스형 컴포넌트에서는 React.createRef()로 호출하고,
함수형 컴포넌트에서는 React.useRef()로 호출한다.

createRef

class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      
    };
    // ref는 이렇게 선언합니다! 
    this.text = React.createRef(); // text는 그냥 변수명임.
  }

  componentDidMount(){
    console.log(this.text);
    console.log(this.text.current); // current를 써야 노드 접근이 됨.
  }
render() {
    
    return (
      ...
        <div>
          <input type="text" ref={this.text}/>
        </div>

useRef

const nameInput = useRef();
console.log(nameInput.current)

<input ref={nameInput}/>

State 관리

setState

import React from 'react';

class App extends React.Component {

  constructor(props){
    super(props);
    this.state = {
      count: 3,
    };
  }
  
  addNemo = () => {
    this.setState({count: this.state.count + 1}) // key는 count, value는 this.state.count
  }

  removeNemo = () => {
    if (this.state.count > 0) {
      this.setState({count: this.state.count - 1}) // 계속 줄다보면 this.state.count가 0 이하가 되는데 이때는 UX를 고려하여 alert을 날려주자.
    } else {
      alert('더 이상은 naver...!')
    }
  }

  render() {
    
    const nemo_count = Array.from({length: this.state.count}, (item, index) => index)
    
    return (
      <div className="App">
        {nemo_count.map((num, index) => { // 돔 구조 안에서 map을 이용한 반복문을 사용하기 위해 {} bracket으로 감싸주었음.
          return (
            <div key={index} style={{
              width: '150px',
              height: '150px',
              backgroundColor: '#eee',
              margin: '10px'
            }}>
              nemo
            </div>
          )
        })}
        <button onClick={this.addNemo}>+</button>
        <button onClick={this.removeNemo}>-</button>
      </div>
    );
  }
}
export default App;

useState

import React from "react";

const Nemo = (props) => {
  
  const [count, setCount] = React.useState(3); // 함수형 컴포넌트에서 state 값을 변경하는 법, React.useState()를 사용해서 위에서 import 하지 않고도 사용할 수 있었음.
  const nemo_count = Array.from({length: count}, (item, index) => index) // 함수형 컴포넌트에서는 this를 사용하지 않음.
  
  const addNemo = () => {
    setCount(count + 1); // 매개변수의 값을 count에 할당해주는것임.
  }
  
  const removeNemo = () => {
    setCount(count > 0 ? count - 1 : 0); // 삼항 조건식
  }
  
  return (
    <div className="App">
      {nemo_count.map((num, index) => { // 돔 구조 안에서 map을 이용한 반복문을 사용하기 위해 {} bracket으로 감싸주었음.
          return (
            <div key={index} style={{
              width: '150px',
              height: '150px',
              backgroundColor: '#eee',
              margin: '10px'
            }}>
              nemo
            </div>
          )
        })}
        <button onClick={addNemo}>+</button>
        <button onClick={removeNemo}>-</button>
    </div>
  );
};

export default Nemo;

Event Listener

import React from 'react';
import Nemo from './Nemo';

class App extends React.Component {
  constructor(props) {
    super(props)
    this.div = React.createRef(); // ref로 이벤트 리스너 추가할 노드 잡기.
  }
  
  hoverEvent = (e) => { // 매개변수에 e(관습적)로 이벤트를 받아옴.
    e.target.style.backgroundColor = "red"
    // 여기서 e는 마우스 오버, e.target은 this.div.current 노드가 됨.
  }
  
  componentDidMount() { // 마운트가 완료되고 불러와야 dom에 문제없이 접근할 수 있음.
    this.div.current.addEventListener("mouseover", this.hoverEvent)
  }
  
  componentWillUnmount() { // 이벤트 리스너는 반드시! 언마운트 될때를 고려해서 제거해줘야 함.
    this.div.current.removeEventListener("mouseover", this.hoverEvent) // 이때 사용하는 메서드는 removeEventListener
  }
  
  render() {
    
    return (
      <div className="App" ref={this.div}>
        <Nemo ></Nemo>
      </div>
    );
  }
}
export default App;

useEffect

함수형 컴포넌트에서 라이프 사이클에 따라 동작을 추가하는 방법.
최초 렌더링 시에는 어떤 경우에든 반드시! useEffect의 콜백 함수가 한번은 동작함.

// dependency가 없는 방법. -> 
// 렌더링 직후, 어떤 값이든 변화(부모 컴포넌트가 변화해도)만 생기면 콜백 함수가 실행됨.
useEffect(() => {});
// dependency에 빈 배열을 넣는 방법. -> 렌더링 직후 한 번만 콜백 함수 실행됨.
useEffect(() => {}, []);
// dependency에 객체나 변수를 넣는 방법. -> 렌더링 직후, 배열 내 변수가 변할때마다 콜백 함수가 실행됨.
useEffect(() => {}, [변수 혹은 오브젝트]);
// return을 주면 언마운트 시에 동작시킬 함수를 넣을 수 있음.
// 이를 cleanup 함수라고 표현함.
useEffect(() => {
  console.log("표시");
  return () => console.log("비표시");
}, []);

더 알아보면 좋을 내용

좋은 웹페이지 즐겨찾기