자바스크립트의 상태관리 라이브러리
세개 중 Redux를 가장 많이 사용한다
데이터들을 어려 모듈(컨텍스트)에 걸쳐서 공유하거나 주고받아야할 때
기존에는 probs를 주고 받았는데 굉장히 많은 컴포넌트가 많은 경우나 뎁스가 깊을 경우 또는 모든 컴포넌트가 참조해야하는 경우 등에 문제가 생긴다
자식 컴포넌트들 간의 다이렉트 데이터 전달은은 불가능하다
자식 컴포넌트들 간의 데이터를 주고받을 때는 상태를 관리하는 부모 컴포넌틀르 통해서 주고 받는다
자식끼리 데이터를 주고 받으려면 자식에서 부모로 갔다가 다시 다른 자식으로 가야한다
그래서 자식이 많아지면 상태 관리가 복잡해진다
상태를 관리하는 상위 컴포넌트에서 계속 내려 받아야하는 여기서 Props drilling 이슈가 생긴다
해당 데이터를 쓰지 않는 컴포넌트에서도 다른 컴포넌트로 데이터를 전달하는 과정이 필요하고 이로 인해 복잡해진다
모든 컴포넌트에서 접근이 가능한 전역 장소에 접근해서 데이터를 다이렉트로 가져오면 Props drilling 이슈가 해결된다
Redux도 전역 장소를 만들어 상태관리를 한다
Redux에는 아래 네가지가 필요하다
Provider - 리액트 앱에 스토어를 쉽게 연결하기 위한 컴포넌트이다
combineReducer - 여러 리듀서를 묶어준다(리듀서는 여러개일 수 있음)
useSelector - redux의 state 조회, Store에 있는 데이터들을 조회한다
useDispatch - 생성한 action을 실행한다
UI에서 Provider가 Reducer에 요청하고 액션을 실행하는게 유useDispatch, Redux의 state를 조회하는 것이 useSelector이다
이름과 전화번호를 받아 추가하고 이름으로 해당 정보를 찾는 웹페이지를 만든다
데이터가 어딘가에 저장되어야하는데 보통은 데이터베이터를 쓰지만
이번 실습에서는 배열에 저장해서 쓸 것이다
npm install redux react-redux
홈페이지 접속
https://react-bootstrap.github.io/
홈페이지에서 Get started 선택

Installation 확인

터미널에서 실행
npm install react-bootstrap bootstrap

import React, {useState} from 'react';
import {Form, Button} from 'react-bootstrap'
import { useDispatch } from 'react-redux';
const ContactForm = () =>{
const [name, setName] = useState('');
const [phoneNumber, setPhoneNumber] = useState(0);
const dispatch = useDispatch(); // 생성된 액션을 실행하기 위해 useDispatch 생성
const addContact = (event) => {
event.preventDefault();
dispatch({
type: 'ADD_CONTACT',
payload : {name, phoneNumber},
});
}
// 입력한 것을 읽어와서 저장해야됨
// 이벤트가 onchange 발생할 때 입력된 값을 밸류값을 setName해서 준다
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;
import React from 'react';
import SearchBox from './SearchBox';
import ContactItem from './ContactItem';
import { useSelector } from 'react-redux';
const ContactList = () => {
const contactList = useSelector((state) => state.contactList);
return (
<div>
<SearchBox />
{contactList.map((item) => (
<ContactItem item={item} />
))}
</div>
);
}
export default ContactList;
import React from 'react';
import { Col, Row } from 'react-bootstrap';
const ContactItem = ({ item }) => {
return (
<Row>
<Col lg={1}>
<br/>
<img
width={50}
src="https://i1.sndcdn.com/avatars-000373844735-9n06kq-t500x500.jpg"
alt=''
/>
</Col>
<Col lg={11}>
<div>{item.name}</div>
<div>{item.phoneNumber}</div>
</Col>
</Row>
);
}
export default ContactItem;
import React from 'react';
import { Button, Col, Form, Row } from 'react-bootstrap';
const SearchBox = () => {
return (
<Row>
{/* lg 비율 설정 */}
<Col lg={10}>
<Form.Control type='text' placeholder='이름을 입력해주세요'/>
</Col>
<Col lg={2}>
<Button>찾기</Button>
</Col>
</Row>
);
};
export default SearchBox;
// 왼쪽 화면에 이름과 전화번호 등록창
// 오른쪽 화면에 이름으로 정보를 찾는 창 구현
import './App.css';
import 'bootstrap/dist/css/bootstrap.min.css'
import {Container, Row, Col} from 'react-bootstrap'
import ContactForm from './components/ContactForm'
import ContactList from './components/ContactList'
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;
.title{
text-align: center;
}
import {createStore} from 'redux';
import reducer from './reducer/reducer'
let store = createStore(reducer);
export default store;
// 리듀서 부를 때 배열로 초기화
let initialState = {
contactList: [],
};
// 리듀서는 스테이트와 액션을 가져야한다
function reducer(state = initialState, 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;
import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
import store from './store'; // 추가
import { Provider } from 'react-redux'; // 추가
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
// 수정
<Provider store={store}>
<App />
</Provider>
);
reportWebVitals();

오늘 한 것이 리액트의 핵심이다
Store라는 전역 저장소를 만들고
Action과 State를 가진 Reducer를 만든다
연결해주는 건 Provider를 만들어서 써야되고
값을 가지고 오는 것에 있어서 Selector로 값을 가져왔다
React 실습을 하는 중에 코드를 수정한 것이 웹페이지에 적용 안되고 버벅거리는 문제가 생겼다
적용이 안되는게 잘못 작성한 내 문제인 줄 알았는데
터미널에서 Ctrl + c 로 실행중인 것을 취소하고 npm start를 다시 입력하니까 잘 실행되었다
기계든 프로그램이든 잘 안 될 땐 껐다가 켜기:)
오늘 수업은 어려웠다. 아직 제대로 이해를 못해서인지 열심히 따라 치긴했는데 많이 어려웠다.
찾아보니 오늘 배운 예제가 Do it! 리액트 프로그래밍 정석에 나오는 예제와 비슷해보여 책을 구매하던 빌리던지 해서 책으로 다시 연습해봐야 될 것 같다.