React-4일차

이주열·2022년 6월 29일

학습한 내용

Props drilling 문제

  • Component간의 정보 공유의 문제
  • 자식 컴포넌트들 간의 다이렉트 데이터 전달은 불가능
  • 자식 컴포넌트들 간의 데이터를 주고 받을 때는 상태를 관리하는 부모
    컴포넌트를 통해서 주고 받는다.
  • 자식이 많아진다면 상태 관리가 매우 복잡해진다.
  • 상태를 관리하는 상위 컴포넌트에서 계속 내려 받아야한다.
  • 위 문제를 해결하는 상태관리 툴 -> React Context, Redux, Mobx
  • 전역 상태 저장소를 만들고, 어디서든 접근할 수 있도록 하여 문제 해결

React - 리덕스(redux)

  • 자바스크립트 상태관리 라이브러리

  • Node.js 모듈에서 출발

  • Provider : react-redux라이브러리 안에 있는 컴포넌트입니다.
    - 리액트 앱에 스토어를 쉽게 연결하기 위한 컴포넌트 입니다.

  • combineReducer : redux모듈이 제공하는 함수이다.
    - 만든 모든 리듀서들을 통합하여 하나의 리듀서로 쓰기 위한 함수이다

  • useSelector : redux의 state조회 (즉, 스토어에 있는 데이터들 조회)

  • useDispatch : 생성한 action 실행

실습. 주소록 만들기

구현 과정
1) 왼쪽은 연락처 등록하는 폼, 오른쪽은 연락처 리스트와 검색창
2) 리스트에 유저 이름과 전화번호를 추가 기능
3) 정보 저장은 배열로 저장
4) 사용자가 유저를 이름검색으로 찾을 수 있다.

  1. 프로젝트 만들기
  • npx create-react-app 0629_proccontact
  • cd 0629_proccontact : 경로 접속
  • npm start : 구동
  1. 리덕스 패키지 설치
  • npm install redux react-redux
  1. react-bootstrap 설치
import {사용하는 기능} from 'react-bootstrap';
import 'bootstrap/dist/css/bootstrap.min.css';

UI설정을 위한 코드
4. App.js 작성

import './App.css';
import {Container, Row, Col} from 'react-bootstrap';
import ContactForm from './components/ContactForm';
import ContactList from './components/ContactList';
import 'bootstrap/dist/css/bootstrap.min.css';

function App() {
  return (
    <div className="App">
      <h1 className="title">연락처</h1>
      <Container>
        <Row>
          <Col>
            <ContactForm></ContactForm>
          </Col>
          <Col>
            <ContactList></ContactList>
          </Col>
        </Row>

      </Container>
    </div>
  );
}

export default App;
  • 왼쪽 col은 정보 입력하는 곳 : ContactForm
  • 오른쪽 col은 정보 찾는 곳 : ContactList
  • 둘 다 컴포넌트화 시켜서 작성
  1. App.css 적용
.title{
  text-align: center;
}
  1. ContactForm.js
  • 왼쪽 정보 입력 컴포넌트
  • src - components 폴더 안에 생성
  • 부트스트랩에서 코드 가져와 수정
import React from 'react';
import {Form, Button} from 'react-bootstrap';

const ContactForm = () => {
    return(
        <Form>
            <Form.Group className="mb-3" controlId="formName">
                <Form.Label>이름</Form.Label>
                <Form.Control type="text" placeholder="이름을 입력해주세요."/>
            </Form.Group>

            <Form.Group className="mb-3" controlId="formContact">
                <Form.Label>전화번호</Form.Label>
                <Form.Control type="number" placeholder="전화번호를 입력해주세요."/>
            </Form.Group>

            <Button variant="primary" type="submit">
                추가
            </Button>
        </Form>
    );
};

export default ContactForm;
  1. ContactList.js
  • 오른쪽 정보 검색 컴포넌트
  • SearchBox, ContactItem 컴포넌트 불러옴
import React from 'react';
import SearchBox from './SearchBox';
import ContactItem from './ContactItem';

const ContactList = () =>{
    return(
        <div>
            <SearchBox></SearchBox>
            <ContactItem></ContactItem>
        </div>
    );
};

export default ContactList;
  1. SearchBox.js
  • lg={10}은 비율을 설정하는 것
import React from "react";
import { Form, Button, Col, Row } from "react-bootstrap";

const SearchBox = () =>{
    return(
        <Row>
            <Col lg={10}>
                <Form.Control type="text" placeholder="이름을 입력해주세요." />
            </Col>
            <Col lg={2}>
                <Button>찾기</Button>
            </Col>
        </Row>
    );
}

export default SearchBox;
  1. ContactItem.js
  • 정보 리스트 보여주는 컴포넌트
  • lg={2}은 비율
  • 나중에 이름과, 전화번호 들어갈 영역만 설정
import React from 'react';
import {Row, Col} from 'react-bootstrap';

const ContactItem = () =>{
    return(
        <Row>
            <Col lg={1}>
                <img width={50} src="https://upload.wikimedia.org/wikipedia/commons/thumb/b/bc/Unknown_person.jpg/925px-Unknown_person.jpg" alt="" />
            </Col>
            <Col lg={11}>
                <div></div>
                <div></div>
            </Col>
        </Row>
    );
};

export default ContactItem;

기능 추가를 위한 코드
10. store.js

  • 전역 저장소를 만드는 과정
  • src - store.js
  • reducer 추가
import {createStore} from 'redux';
import reducer from './reducer/reducer';

let store = createStore(reducer);

export default store;
  1. reducer.js
  • 여러 reducer가 있을 수 있기에 src하위 폴더를 만들고 파일 생성
  • src - reducer - reducer.js
// 배열 만들기
let initialState = {
    contactList: [],
};

//reducer는 state 와 action으로 이루어 진다.
function reducer(state = initialState, action){
    // 변수 type, payload에 따라 action이 수행
    const {type, payload} = action;
    switch(type){
        case 'ADD_CONTACT':
            return{
                ...state,
                contactList:[
                    ...state.contactList,
                    {
                        name: action.payload.name,
                        phoneNumber: action.payload.phoneNumber,
                    },
                ],
            };
        default : 
            return {...state};    
    }
}

export default reducer;
  1. index.js
  • store랑 reducer를 연결하는 것이 provider
  • provider 적용을 위해 root 변경과 import추가
import store from './store';
import { Provider } from 'react-redux';

root.render(
  <Provider store={store}>
    <App />
  </Provider>
);
  1. ContactForm.js 수정
  • 데이터를 저장할 setName, setPhoneNumber
  • action 실행을 위해 useDispatch 추가
import React from 'react';
import {Form, Button} from 'react-bootstrap';
import { useState } from 'react';
import { useDispatch } from 'react-redux';

const ContactForm = () => {
    const [name, setName] = useState('');
    const [phoneNumber, setPhoneNumber] = useState(0);
    // action 실행을 위한 dispatch
    const dispatch = useDispatch();

    const addContact = (event) => {
        event.preventDefault();
        dispatch({
            type: 'ADD_CONTACT',
            payload: { name, phoneNumber },
        });
    };

    return(
        <Form onSubmit={addContact}>
            <Form.Group className="mb-3" controlId="formName">
                <Form.Label>이름</Form.Label>
                <Form.Control type="text" placeholder="이름을 입력해주세요."
                onChange={(event) => setName(event.target.value)} />
            </Form.Group>

            <Form.Group className="mb-3" controlId="formContact">
                <Form.Label>전화번호</Form.Label>
                <Form.Control type="number" placeholder="전화번호를 입력해주세요."
                onChange={(event) => setPhoneNumber(event.target.value)} />
            </Form.Group>

            <Button variant="primary" type="submit">
                추가
            </Button>
        </Form>
    );
};

export default ContactForm;
  1. ContactList.js 수정
  • 저장한 것을 화면에 나타내기
  • useSelector은 redux의 state 조회
import React from 'react';
import SearchBox from './SearchBox';
import ContactItem from './ContactItem';
import { useSelector } from 'react-redux';

const ContactList = () =>{
    //redux의 state 조회
    const contactList = useSelector((state) => state.contactList);

    return(
        <div>
            <SearchBox></SearchBox>
            {contactList.map((item) => (
                <ContactItem item={item}></ContactItem>
            ))}
        </div>
    );
};

export default ContactList;

15.ContactItem.js 수정

  • 추가한 item을 받는 것이 필요함
  • 처음 비워 둔 두 div영역에 추가
import React from 'react';
import {Row, Col} from 'react-bootstrap';

const ContactItem = ({ item }) =>{
    return(
        <Row>
            <Col lg={1}>
                <img width={50} src="https://upload.wikimedia.org/wikipedia/commons/thumb/b/bc/Unknown_person.jpg/925px-Unknown_person.jpg" alt="" />
            </Col>
            <Col lg={11}>
                <div>{item.name}</div>
                <div>{item.phoneNumber}</div>
            </Col>
        </Row>
    );
};

export default ContactItem;

최종 실행

이름과 전화번호 작성하고 추가버튼을 누르면

여러 개를 추가하며도 잘 나오는 것을 확인 가능

정리

  • 많은 정보와 데이터를 공유하면서 사용해야 되는 경우 문제가 발생하는데, 그 문제가 Props drilling
  • 그 문제를 해결하는 상태관리 툴 중 redux가 가장 핫함.
  • 전연 상태 저장소를 만들고 거기에 접근해서 사용하도록 설정
  • 저장소를 만들고 store쪽으로 요청을 할 때 필요한 것이 action을 가지는 reducer, 연결해주는 것이 provider
  • 이렇게 연결해서 값을 가지고 오는 것이 useSelector, 실행에 필요한 것이 useDispatch

학습한 내용 중 어려웠던 점 또는 해결못한 것들

해결방법 작성

학습 소감

오타와 대,소문자의 틀림으로 인해 많은 오류가 발생했었다. 톡히 이름이 비슷한 변수, 컴포넌트들을 사용하는 과정에서 오타가 많이 발생했고, 컴포넌트 호출하는 과정에서 대문자를 소문자를 적는 실수가 많았다. 코드를 작성할 때 다시 한번 점검하는 습관이 필요하다.
또한, 오늘 주소록을 만들면서 구현 과정을 설계하는 것이 중요하다고 느꼈다. 천천히 하나씩 진행하면서 오류도 잡기 편했고, 단계가 있기에 진행하는 부분에도 도움이 되었다. 어떤 프로젝트를 하던 설계 과정을 잘 하도록 노력하자

profile
예비 프론트엔드 개발자

0개의 댓글