2022-06-29
JavaScript의 상태관리 라이브러리
React Context
도 상태관리 툴 중의 하나. 그 외에 Mobx
등.
Redux의 본질은 Node.js모듈
State는 component 안에서 관리된다.
Component간의 정보 공유에서 알아둘 것 :
컴포넌트와 별개로 스토어라는 공간에 앱에서 필요한 상태를 담는다.
컴포넌트에서 상태 정보가 필요할 때 스토어에 접근
- 앱에서 스토어에 운반할 데이터(주문서)
- 자바스크립트 객체 형식으로 되어있다
- Action을 Store에 바로 전달하는 것이 아니라, Reducer에 전달해야함
Reducer가 주문을 보고 Store의 상태를 업데이트 한다.
Action을 Reducer에 전달하기 위해서는 dispatch() 메소르를 사용해야한다.
Action 객체
가 dispatch()
메소드에 전달됨->dispatch(액션)을 통해 Reducer 호출-> Reducer
는 새로운 Store
생성
왜 이런가 하면, 데이터는 한 방향으로만 흘러야하기 때문
react-redux 라이브러리 안에 있는 컴포넌트.
리액트 앱에 스토어를 쉽게 연결하기 위한 컴포넌트
redux 모듈이 제공하는 함수
만든 모든 리듀서들을 통합하여 하나의 리듀서로 쓸 수 있음
redux의 state 조회 (스토어에 있는 데이터들 조회)
생성한 action 실행
npm install redux react-redux
App.js
import logo from './logo.svg';
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;
App.css
title{
text-align: center;
}
index.js
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>
);
// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();
store.js
import { createStore } from 'redux';
import reducer from './reducer/reducer';
let store = createStore(reducer);
export default store;
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();
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;
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 { Row, Col, Form, Button } 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;
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;
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;
추가하는 것 자체는 기능하는데 입력한 값이 제대로 전해지지 않음
ContactForm.js 에 부트스트랩에서 쓰던 명칭 formPassword를 formContact로 바꾸어주니 잘 나오는 줄 알았는데,
<Form.Group className="mb-3" controlId="formContact">
알고보니 전화번호 입력칸에 number값을 줘서 하이픈(-)을 넣었을 때 추가 버튼이 작동하지 않던 거였다.
하하하... 오류 찾기 즐겁다...~