200810-200816_TIL

|

8월 10일 (월)

  • 에듀캐스트 장고&리액트 리액트 강의를 다 수강했다. 했지만, 아직 이해안가는 영역이 더 많기에 나머지 강의도 수강하면서 익혀야겠다.

8월 11(화)

  • 리액트로 인스타 모방 사이트를 만들어보기전 안들었던 DRF강의를 듣고있다. DRF도 아리송한 개념들이라 어렵다.

8월 12일 (수)

  • DRF 남은 강의를 모두 수강했다. 아직도 아리송하다.

8월 13일 (목)

  • 드디어 리액트와 함께 SPA 방식으로 구현하는 강의를 수강하고 있는 중이다. 그래도 반복해보니 조금씩은 이해가 가는거 같다. 더 열심히 해서 얼른 취업해야겠다!!!

8월 14일 (금)

  • 친구랑 하는 웹페이지 디자인을 일부 구현했다. 기존에 제공되어있는 리소스에 계속 얹히는 식으로 하니 갈수록 좀… 그렇긴 하다.. 일단 레이아웃 구조를 좀더 의미있게 만들 수 있게 공부하고 생각해보면서 해봐야겠다.

8월 15, 16일 (토, 일)

  • 잠시 휴식을 가지러 부산을 다녀왔다. 간만에 간 부산의 날씨는 더웠지만 바다들이 예뻐서 흡족스러웠다.

React 함수형 컴포넌트와 필수 Hook

|

에듀캐스트 장고&리액트 강의를 듣고 정리하는 글이다.

클래스형 컴포넌트의 한계

  • 클래스가 코드 재사용성과 코드 구성을 더 어렵게 만든다.
  • 자바스크립트의 this는 다른 언어와 다르게 작동하며, 개발자는 이벤트 핸들러가 등록되는 방법을 기억해야만 한다.
  • 부수적으로 작성해야하는 코드가 많다.
  • 서로 연관성이 없는 다수 로직을 하나의 생명주기 메서드에서 구현하는 경우가 많다.
  • 코드 압축이 잘 안되는 경우가 있고, 컴파일 단계에서 코드 최적화를 어렵게 만든다.
  • componentDidMount에서 등록하고 ComponentWillUnmount에서 해제를 깜발할 수 있다. (setInterval같은 함수 해제 깜박하는 등)

함수형 컴포넌트를 사용하자.

함수형 컴포넌트

  • 클래스형 컴포넌트에 적용했던 것들을 대부분 적용 가능 (Hook을 활용)
  • 현재 리액트 팀에서도 함수형 컴포넌트와 Hook 개발에 집중하고 있다.
    • 그래서 리액트를 시작할 때 함수형 컴포넌트를 쓰기를 권장한다.
    • 클래스 컴포넌트에 대한 호환성을 보장한다.

다음은 클래스형 컴포넌트 예시인데, 아래처럼 바꿀 수 있다.

클래스형 컴포넌트

class Message1 extends React.Component{
  render(){
    return (
      <div>{this.props.message}</div>
    )
  }
}

####함수형 컴포넌트

const Message2 = (props) => (
  <div>{props.message}</div>
);

const Message3 = ({message}) => (
  <div>{message}</div>
);

필수 Hooks (useState, useEffect, userCallback)

  • 리액트 버전 16.8에 새로이 추가되었다.
  • Hook을 통해 함수형 컴포넌트에서도 상태값과 여러 React의 기능을 활용할 수 있다.
    • props, state, context, refs, life-cycle에 대해 보다 직관적인 API를 제공한다.
    • 같은 로직을 한 곳으로 모을 수 있어서 가독성에 좋다.
    • 클래스형 컴포넌트에서 사용하려면, 커스텀 Wrapper 컴포넌트가 필요하다.

userState 훅

컴포넌트 내에서 상태값을 유지/변경하고 싶을 때 사용한다. 단, 주의해야할 점으로 useState 훅은 이전 상태값을 모두 지우기 때문에, 통으로 변경해주어야 한다.

// 아래처럼 useState 함수를 import 해준다.
import {useState} from "react";

function App2() {
  const [value1, setValue1] = useState(0);
  const [value2, setValue2] = useState(0);
  const [value, setValue] = useState({ value1: 0, value2: 0 }); // 상태값을 바꿀때 다 바꿔줘야한다.
  const onClick = () => {
    setValue((prevState) => ({ ...prevState, value1: 10 }));
  };
  return (
    <div>
      Hello App2
      <hr />
      {JSON.stringify(value)}
      <button onClick={onClick}>Button</button>
    </div>
  );
}

useEffect 훅

생명주기의 componentDidMount와 componentDidUpdate에 대응한다.

  useEffect(() => {});  // render 시에 호출
  useEffect(() => {}, []); // mount 시에만 호출
  useEffect(() => {}, [value]); // value가 변경될 시에 호출
  useEffect(() => {
    return () => {};
  }, [value]); // unmount 시에 호출된다. clearInterval 같은 곳에 사용

React immer를 활용한 손쉬운 불변객체 다루기

|

에듀캐스트 장고&리액트 강의를 듣고 정리하는 글이다.

불변성 (Immutable)

리액트에서는 불변성을 유지하면서, 상탯값을 업데이트해야만 한다.

object는 다음과 같이 처리하여 불변성을 유지할 수 있다.

const todo ={
  name: 'immer 이해하기'
  is_compelted: false,
};

const newState = {
  ...todo,
  is_compelted: true
}

하지만 배열의 경우에서는 유지하기가 힘들다.

const fruits = ["orange", "apple", "lemon", "banana"]

// 제거된 객체들을 반환하며, fruits 객체를 변경한다.
fruits.splie(1, 2, "strawberry")


// 아래처럼 하면 fruits의 불변성을 유지할 수 있지만, 가독성이나 관리가 쉽지 않다.
const newFruites = [
  ...fruits.slice(0, 1),
  "strawberry",
  ...fruits.slice(3),
]

// immer를 사용하면, 익숙한 코드로 불변성을 지킬 수 있다.
const newFruites = produce(fruits, draft => {
  draft.splice(1, 2, "strawberry");
})

immer 설치

yar add immer

// node.js

const { produce } = require('immer');

// const fruits = ['오렌지', '사과', '레몬', '바나나'];

// const newFruits = produce(fruits, (draft) => {
//   draft.splice(1, 2, '딸기');
// });

// console.log(newFruits);

const baseState = [
  {
    todo: 'Learn ES6+',
    done: true,
  },
  {
    todo: 'Try immer',
    done: false,
  },
];

// const newbaseState = [...baseState, { todo: 'Tweet about it' }];
// newbaseState[1].done = true;

const newbaseState = [
  ...baseState.map((tweet, index) =>
    index === 1 ? { ...tweet, done: true } : tweet,
  ),
  { todo: 'Tweet about it' },
];

const newimmerState = produce(baseState, (draft) => {
  draft[1].done = true;
  draft.push({ todo: 'Tweet about it' });
});

console.log(baseState);
console.log(newbaseState);
console.log(newimmerState);

React 간단한 TODO List 만들어 보기

|

에듀캐스트 장고&리액트 강의를 듣고 정리하는 글이다.

간단한 TODO List 만들어 보기

import React from 'react';
import { List, Input } from 'antd';

// class TodoItem extends React.Component {
//   render() {
//     const { todo } = this.props;
//     return <li>{todo}</li>;
//   }
// }

const TodoItem = ({ todo }) => <li>{todo}</li>;

class ToDoList extends React.Component {
  state = {
    todoList: ['파이썬 익히기', '장고 익히기'],
    current: '',
  };
  onChange = (e) => {
    const { value } = e.target;
    this.setState({
      current: value,
    });
  };
  onKeyDown = (e) => {
    if (e.keyCode === 13) {
      // ENTER KEY
      const { todoList, current } = this.state;
      if (current.trim().length > 0) {
        this.setState({
          current: '',
          todoList: [...todoList, current.trim()], // state는 불변으로 유지하는게 좋으니 복사 사용
        });
      }
    }
  };
  render() {
    return (
      <div style=>
        <List
          header={'Todo List'}
          dataSource={this.state.todoList}
          bordered={true}
          renderItem={(todo) => <List.Item>{todo}</List.Item>}
          style=
        />
        <Input
          type="text"
          value={this.state.current}
          placeholder={'할일을 입력해주세요.'}
          onChange={this.onChange}
          onKeyDown={this.onKeyDown}
        />

        {/* <ul>
          {this.state.todoList.map((todo, index) => (
            <TodoItem key={index} todo={todo} /> // 순회돌면 key 필요
          ))}
        </ul>
        <input
          type="text"
          placeholder="할일을 입력해주세요."
          value={this.state.current}
          onChange={this.onChange}
          onKeyDown={this.onKeyDown}
        />
        <hr /> */}
        {/* {JSON.stringify(this.state)} */}
      </div>
    );
  }
}

export default ToDoList;

React 이벤트 처리하기 & 리액트 컴포넌트 만들기(클릭 카운터)

|

에듀캐스트 장고&리액트 강의를 듣고 정리하는 글이다.

이벤트

컴포넌트에는 여러 이벤트가 발생 -> 이벤트에 대한 처리를 커스텀 웹브라우저의 HTML이벤트를 기본적으로 지원

  • 이벤트 핸들러 속성명은 camelCase로만 작성 (HTML에서는 onclick, 리액트는 onClick)
  • 이벤트 핸들러에는 필히 함수를 지정 (HTML에서는 문자열로 코드를 지정)

DOM 요소에만 이벤트가 지원한다.

  • 커스텀 리액트 컴포넌트에서는 HTML 이벤트를 지원하지 않는다.
  • 하지만 내부 Element에 DOM요소를 담아, 핸들러를 지정할 수 있다.
import React from 'react';
import PropTypes from 'prop-types';
import Counter from 'Counter';
import 'App.css';

class App extends React.Component {
  state = {
    myquery: '',
    language: '',
  };
  onChange = (e) => {
    const { name, value } = e.target;
    this.setState({
      [name]: value,
    });
  };
  render() {
    return (
      <>
        <Counter onClick={() => console.log('clicked')} />
        <input name="myquery" onChange={this.onChange} />
        <input name="language" onChange={this.onChange} />
        <hr></hr>
        {JSON.stringify(this.state)}
      </>
    );
  }
}

export default App;

리액트 컴포넌트 만들기 (클릭 카운터)

App.js

import React from 'react';
import PropTypes from 'prop-types';
import Counter from 'Counter';
import 'App.css';

class App extends React.Component {
  render() {
    return (
      <div>
        <Counter />
        <Counter color="green" />
        <Counter color="blue" />
      </div>
    );
  }
}

export default App;

Counter.js

  • defaultPros: 디폴트 속성값 정해준다.
  • proTypes: 속성값은 자료형을 정해준다.
import React from 'react';
import PropTypes from 'prop-types';

class Counter extends React.Component {
  static defaultProps = {
    color: 'red',
  };

  static proTypes = {
    color: PropTypes.string,
  };

  state = {
    color: this.props.color,
    value: 0,
  };
  onClick = () => {
    // this.setState({ value: this.state.value } + 1);
    this.setState(({ value: prevValue }) => ({
      value: prevValue + 1,
    }));
  };
  // 우클릭 이벤트
  onContextMenu = (e) => {
    e.preventDefault();
    this.setState(({ value: prevValue }) => ({
      value: prevValue >= 1 ? prevValue - 1 : 0, // 삼항 연산자 참이면 좌측 실행, 거짓이면 우측 실행
    }));
  };
  render() {
    const { color, value } = this.state;
    return (
      <div
        onClick={this.onClick}
        onContextMenu={this.onContextMenu}
        style=
      >
        {value}
      </div>
    );
  }
}

const style = {
  width: '100px',
  height: '100px',
  display: 'inline-block',
  borderRadius: '50px',
  textAlign: 'center',
  lineHeight: '100px',
  userSelect: 'none',
  fontSize: '3rem',
  margin: '1rem',
};

export default Counter;