7장. Class형 컴포넌트 Project

Jung Hyewon·2021년 7월 3일
0

Study.React

목록 보기
7/7
post-thumbnail
post-custom-banner

📌 Class형 컴포넌트 특징

참고 link : 6장. Class형 컴포넌트와 Function형 컴포넌트 (+Hook)

🐱 Github

habit-tracker project

📍 Project 소개 ( habit-tracker )

습관관리 프로젝트

  • 습관들(Habits)을 추가할 수도 있고 삭제할 수도 있으며
    원하는 습관의 횟수를 추가, 감소 할 수 있다.
  • 결과 Page
    habit-tracker UI

📝 실습 Code

  • app.jsx

    • state
      habits
    • render
      <Navbar/>
      <Habits/>
import React, { Component, Fragment } from 'react';
import './app.css';
import Habits from './components/habits';
import Navbar from './components/navbar';
//
class App extends Component {
  //'습관들(habits)'을 state로 설정
  state = {
    habits: [
      { id: 1, name: 'Reading', count: 0 },
      { id: 2, name: 'Running', count: 0 },
      { id: 3, name: 'Coding', count: 0 }
    ]
  }
  /**
  state의 count를 1씩 증가시키는 함수 (map함수 이용)
  map() : 현재 state의 habits을 순차적으로 돌며 
  하위 컴포넌트에서 받은 '습관(habit)'의 id값과 
  현재 state로 설정된 '습관들(habits)'의 id값을 비교하여 
  id 값이 같은 경우에(== ' + ' 버튼를 눌렀을 때 전달받은 habit)
  state의 해당 habit의 count값을 1 더해준다.
  (아래 코드의 item은 'habits'의 'habit'을 의미 / item이란 변수명은 코더의 마음대로 설정)
  */
  handleIncrement = (habit) => {
    const copyHabits = this.state.habits.map(item => {
      if (item.id === habit.id) {
        return { ...habit, count: habit.count + 1 }
      }
      return item;
    })
    this.setState({
      habits: copyHabits
    })
  }
  /**
  state의 count를 1씩 감소시키는 함수 (map함수 이용)
  위의 handleIncrement와 동일한 개념으로 동작하고,
  추가로 마이너스가 연산되었을 때 0미만으로 떨어지는 경우
  state를 0으로 설정해준다.
  */
  handleDecrement = (habit) => {
    const copyHabits = this.state.habits.map(item => {
      if (item.id === habit.id) {
        const count = habit.count - 1;
        return { ...habit, count: count < 0 ? 0 : count };
      }
      return item;
    })
    this.setState({
      habits: copyHabits
    })
  }
  /**
  habit을 삭제하는 함수 (filter함수 이용)
  filter() : 현재 state의 habits을 순차적으로 돌며 
  선택된 habit인 경우를 제외하고 남은 habits를 leftHabits에 담고 이를 현재 state값에 적용한다.
  (== 선택된 habit만 제거한다.)
  (아래 코드의 item은 'habits'의 'habit'을 의미 / item이란 변수명은 코더의 마음대로 설정)
  */
  handleDelete = (habit) => {
    const leftHabits = this.state.habits.filter(item => item.id !== habit.id);
    this.setState({
      habits: leftHabits
    })
  }
  /**
  habit을 추가하는 함수
  현재의 state값을 복사하고(Spread Operator)
  추가로 param으로 받은 name을 habit의 name으로 설정하고 추가해준다.
  id값은 중복을 피해주기 위해 Date.now()함수를 이용하였다.
  */
  handleAdd = (name) => {
    const habitsCopy = [...this.state.habits, 
                        { id: Date.now(), name: name, count: 0 }
                       ]
    this.setState({ habits: habitsCopy });
  }
  /**
  habits속 모든 habit의 count를 0으로 설정해주는 함수
  */
  handleReset = () => {
    const habits = this.state.habits.map((habit) => {
      if (habit.count > 0) {
        return { ...habit, count: 0 };
      }
      return habit;
    });
    this.setState({
      habits
    })
  }
  render() {
    return (
      <Fragment>
        <Navbar totalCount={
            this.state.habits.filter(item => item.count > 0).length
           } 
        />
        <Habits
          habits={this.state.habits}
          onIncrement={this.handleIncrement}
          onDecrement={this.handleDecrement}
          onDelete={this.handleDelete}
          onAdd={this.handleAdd}
          onReset={this.handleReset}
        />
      </Fragment>
    )
  }
}
//
export default App;
    • props
      totalCount
import React, { PureComponent } from 'react';
//
class Navbar extends PureComponent {
    render() {
        return (
            <div className="navbar">
                <i className="navbar-logo fas fa-leaf"></i>
                <span>Habit Tracker</span>
                <span className="navbar-count">{this.props.totalCount}</span>
            </div>
        );
    }
}
//
export default Navbar;
  • habits.jsx

    • props
      habits
      onIncrement / onDecrement / onDelete/ onAdd / onReset
    • render
      <HabitAddForm/>
      <Habit/>
import React, { Component } from 'react';
import Habit from './habit';
import HabitAddForm from './habitAddForm';
import HabitFilter from './habitFilter';
//
class Habits extends Component {
    handleIncrement = (habit) => {
        this.props.onIncrement(habit);
    }
    handleDecrement = (habit) => {
        this.props.onDecrement(habit);
    }
    handleDelete = (habit) => {
        this.props.onDelete(habit);
    }
    handleAdd = (name) => {
        this.props.onAdd(name);
    }
    handleFilter = (name) => {
        this.props.onFilter(name);
    }
    render() {
        return (
            <>
                <HabitAddForm onAdd={this.handleAdd} />
                <HabitFilter onFilter={this.handleFilter} />
                <ul>
                    {
                        this.props.habits.map((habit, index) => {
                            return (
                                <Habit
                                    key={habit.id}
                                    habit={habit}
                                    onIncrement={this.handleIncrement}
                                    onDecrement={this.handleDecrement}
                                    onDelete={this.handleDelete}
                                />
                            )
                        })
                    }
                </ul>
                <button className="habits-reset" 
                  onClick={this.props.onReset}>
                  Reset All
            	</button>
            </>
        );
    }
}
//
export default Habits
  • habitAddForm.jsx

    • props
      onAdd
import React, { memo } from 'react';
//
const HabitAddForm = memo(props => {
    const formRef = React.createRef();
    const inputRef = React.createRef();
    const onSubmit = (e) => {
        e.preventDefault();
        const name = inputRef.current.value;
        name && props.onAdd(name);
        //inputRef.current.value = '';
        formRef.current.reset();
    }
//
    return (
        <form ref={formRef} className="add-from" onSubmit={onSubmit}>
            <input
                ref={inputRef}
                type="text"
                className="add-input"
                placeholder="Habit" />
            <button className="add-button">Add</button>
        </form>
    );
});
//
export default HabitAddForm;
  • habit.jsx

    • props
      habit
      onIncrement / onDecrement / onDelete
import React, { memo } from 'react';
//
const Habit = memo((props) => {
  	//컴포넌트가 UI상 등록이 되었을 때 : 사용자에게 보여질 때
    const componentDidMount = () => {
        console.log(`habit : ${props.habit.name} mounted`);
    }
    //컴포넌트 지우기 전에 호출
    const componentWillUnmount = () => {
        console.log(`habit : ${props.habit.name} will unmount`);
    }
    //컴포넌트리시브받을때
    const componentWillReceiveProps = () => {
        console.log("컴포 리시브 받을 때");
    }
    //props 값을 못 받았을 경우에 대비해 defaultProps설정
    const defaultProps = {
        id: 0,
        name: 'defaultProps',
        count: 0
    }
    const handleIncrement = () => {
        props.onIncrement(props.habit);
    }
    const handleDecrement = () => {
        props.onDecrement(props.habit);
    }
    const handleDelete = () => {
        props.onDelete(props.habit);
    }
    const { name, count } = props.habit;
  //
    return (
        <li className="habit">
            <span className="habiit-name">{name}</span>
            <span className="habit-count">{count}</span>
            <button className="habit-button habit-increase" 
              onClick={handleIncrement} 

            <i className="fas fa-plus-square"></i>
            </button>
            <button className="habit-button habit-decrease" 
              onClick={handleDecrement} 

            <i className="fas fa-minus-square"></i>
            </button>
            <button className="habit-button habit-delete" 
              onClick={handleDelete}  

            <i className="fas fa-trash"></i>
            </button>
        </li>
    )
})
//
export default Habit;
profile
위대한 포부가 위대한 개발자를 만듭니다.
post-custom-banner

0개의 댓글