• Home
  • About
    • Tien02 photo

      Tien02

      Moon is a minimal, one column jekyll theme for your blog.

    • Learn More
    • Facebook
    • Instagram
    • Github
  • Posts
    • All Tags
    • DataBase
    • React
    • Linux
    • Review
  • Projects

React-Tutorial, To Do List

29 May 2019

Reading time ~2 minutes

얼마전에 진행했던 리액트 튜토리얼에 대한 간단한 리뷰를 작성하게 되었다. 소스코드 전체는 여기서 확인 할 수 있으며 학습을 위해 작성한 자료로 사실과 다른 부분이 있을 수있다.(지적해주시면 감사하겠습니다!)

App.js

handleCreate = () => {
  const { input, todos } = this.state;
  this.setState({
    input: '',
    todos: todos.concat({ 
      id: this.id++,
      text: input,
      checked: false
    })
  });
};

  • state 내부의 배열에 원소를 더할 때 절대 push 메소드를 쓰지 않는다. 리액트는 setState() 메소드가 호출 될때 리렌더링 되도록 구현되어 있기 때문에 렌더링이 불필요한 경우에도 일어 날 수 있다. shouldComponentUpdate 와 같은 라이플 사이클 api를 통해 이런 상황을 방지한다. 이를 위해서는 이전 state와 다음 state의 비교가 일어나게 되는데, push 메소드를 사용 할 경우, 같은 배열을 리턴하기 때문에 적절한 비교가 이루어지지 않는다. 반면 concat은 기존배열에 추가하는 원소를 더한 새로운 배열을 리턴함으로 적절한 비교가 가능해진다. (전개연산자를 사용해도 괜찮다.)
handleToggle = (id) => {
        const { todos } = this.state;.
        const index = todos.findIndex(todo => todo.id === id);
        const selectd = todos[index]; 
        const nextTodos = [...todos]; // 배열을 복사
  
        nextTodos[index] = {
            ...selectd,
            checked: !selectd.checked
        };

        this.setState({
            todos: nextTodos
        });
    };
  • javascript의 객체나 배열은 기본적으로 shwallow copy(주소값을 공유)를 수행한다. 때문에 deep copy(값을 복사하여 새로운 메모리를 할당받는다)를 수행하기 위하여 전개연산자를 통해 새로운 배열을 만들어 준다.

TodoListTemplate.js

const TodoListTemplate = ({form, children}) =>{
    return (
        <main className="todo-list-template">
            <div className="title">
                오늘 할 일
            </div>
            <section className="form-wrapper">
                {form}
            </section>
            <section className="todos-wrapper">
                {children}
            </section>
        </main>
    );
};
  • children은 TodoListTemplate 태그 사이의 값이 들어감
  • TodoListTemplate.js 는 함수형 컴포넌트이다. 함수형 컴포넌트는 첫 마운팅 속도에 있어 7%~11% 빠르며 컴포넌트 자체 기능이 없고 props가 들어가면 뷰가 나온다는 것을 명시하기 위해 사용한다. 이때 컴포넌트는 state나 라이플 사이클 api를 전혀 사용하지 않는다.
  • 특히 Redux를 사용하여 컴포넌트들을 구성 할 때, Container 컴포넌트는 클래스형, Presentational 컴포넌트는 함수형 컴포넌트를 사용한다.

TodoItem.js

class TodoItem extends Component {

    shouldComponentUpdate(nextProps, nextState){
        return this.props.checked !== nextProps.checked;
    }

    render(){
        const { text, checked, id, onToggle, onRemove} = this.props;
        return (
            <div className="todo-item" onClick={() => onToggle(id)}>
                <div className="remove" onClick={(e) => {
                    e.stopPropagation();
                    onRemove(id)
                }}>
                    &times;
                </div>
               <div className={`todo-text ${ checked ? ' checked' : '' }`}>
                    <div>{text}</div>
                </div>
                {
                    checked && (<div className='check-mark'>&#x2713;</div> )
                }
            </div>
        );
    }
}
  • onToggle과 같이 파라미터를 넣어줘야 되는 함수는 ()=>onToggle(id)와 같이 작성한다. onToggle(id)를 넘겨줄 경우 해당 함수가 렌더링 될때마다 호출되고, 호출되면 데이터가 변경되고 다시 리렌더링되는 무한반복이 일어날 수 있다
  • 일반 html 태그 내에 onclick은 인라인 js를 실행시키는 것이기 때문에 ()를 붙임으로서 호출을 해주나, 리액트 같은 경우는 addEventHandler와 같이 바인딩하기 때문에 함수 객체만 넘겨준다.
  • 클래스 네임을 동적할당 하기 위해 템플릿 리터럴를 사용하였다.

Reference

https://velopert.com/3480



reacttutorialto do list Share Tweet +1