3. REACT REDUX

Hapjeong Girl·2022년 11월 9일
0

MUTSA_STUDY

목록 보기
9/11
post-thumbnail

3.0 Setup


  1. App.js 생성

    import React from 'react';
    
    function App() {
    	return 'App';
    }
    
    export default App;
  2. Index.js 초기화

    import React from 'react';
    import ReactDOM from 'react-dom';
    import App from './components/App';
  3. index.html 수정

    <!DOCTYPE html>
    <html lang="en">
    
    <head>
      <meta charset="utf-8" />
      <link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
      <meta name="viewport" content="width=device-width, initial-scale=1" />
      <meta name="theme-color" content="#000000" />
      <meta name="description" content="Web site created using create-react-app" />
      <link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
      <link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
      <title>Vanilla Redux</title>
    </head>
    <body>
      <div id="root"></div>
    </body>
    </html>
  4. Index.js 수정 - 2

    import React from 'react';
    import ReactDOM from 'react-dom';
    import App from './components/App';
    
    ReactDOM.render(<App></App>, document.getElementById('root'));
  5. react-redux와 react-router-dom을 설치하자

    yarn add react-redux react-router-dom

    💡 단! 강의를 들을 때 react-router-dom@5.1.2 설치해야 오류 X
  6. routes 폴더를 생성해 Home.js와 Detail.js를 생성

    // Home.js
    export default () => 'Home';
    // Detail.js
    export default () => 'Detail';
  7. App.js 수정

    import React from 'react';
    import { HashRouter as Router, Route } from 'react-router-dom';
    import Home from '../routes/Home';
    import Detail from '../routes/Detail';
    
    function App() {
    	return (
    		<Router>
    			<Route path='/' exact component={Home}></Route>
    			<Route path='/:id' exact component={Detail}></Route>
    		</Router>
    	);
    }
    
    export default App;
  8. Home.js 수정

    import React, { useState } from 'react';
    
    function Home() {
    	const [text, setText] = useState('');
    	function onChange(e) {
    		setText(e.target.value);
    	}
    	function onSubmit(e) {
    		e.preventDefault();
    		console.log(text);
    	}
    	return (
    		<>
    			<h1>To Do</h1>
    			<form onSubmit={onSubmit}>
    				<input type='text' value={text} onChange={onChange} />
    				<button>Add</button>
    			</form>
    			<ul></ul>
    		</>
    	);
    }
    
    export default Home;

3.1 Connecting the Store


  1. store.js 생성

    import { createStore } from 'redux';
    
    const ADD = 'ADD';
    const DELETE = 'DELETE';
    
    export const addToDo = (text) => {
    	return {
    		type: ADD,
    		text
    	};
    };
    
    export const deleteToDo = (id) => {
    	return {
    		type: DELETE,
    		id
    	};
    };
    
    const reducer = (state = [], action) => {
    	switch (action.type) {
    		case ADD:
    			return [{ text: action.text, id: Date.now() }, ...state];
    		case DELETE:
    			return state.filter((toDo) => toDo !== action.id);
    		default:
    			return state;
    	}
    };
    const store = createStore(reducer);
    
    export default store;
  2. Index.js 수정

    import React from 'react';
    import ReactDOM from 'react-dom';
    import App from './components/App';
    import Provider from 'react-redux';
    import store from './store';
    
    ReactDOM.render(
    	<Provider store={store}>
    		<App />
    	</Provider>,
    	document.getElementById('root')
    );

3.2 mapStateToProps


redux state로부터 정보를 가지고 와보자

💡 connect : components들을 store에 연결시켜준다

  1. Home.js 수정

    import React, { useState } from 'react';
    import { connect } from 'react-redux';
    
    function Home({ toDos }) {
    	const [text, setText] = useState('');
    	function onChange(e) {
    		setText(e.target.value);
    	}
    	function onSubmit(e) {
    		e.preventDefault();
    		console.log(text);
    	}
    	return (
    		<>
    			<h1>To Do</h1>
    			<form onSubmit={onSubmit}>
    				<input type='text' value={text} onChange={onChange} />
    				<button>Add</button>
    			</form>
    			<ul>{JSON.stringify(toDos)}</ul>
    		</>
    	);
    }
    function mapStateToProps(state) {
    	return { toDos: state };
    }
    
    export default connect(mapStateToProps)(Home);

3.3 mapDispatchToProps


  1. Home.js

    import React, { useState } from 'react';
    import { connect } from 'react-redux';
    import { actionCreators } from '../store';
    
    function Home({ toDos, addToDo }) {
    	const [text, setText] = useState('');
    	function onChange(e) {
    		setText(e.target.value);
    	}
    	function onSubmit(e) {
    		e.preventDefault();
    		addToDo(text);
    		setText('');
    	}
    	return (
    		<>
    			<h1>To Do</h1>
    			<form onSubmit={onSubmit}>
    				<input type='text' value={text} onChange={onChange} />
    				<button>Add</button>
    			</form>
    			<ul>{JSON.stringify(toDos)}</ul>
    		</>
    	);
    }
    
    function mapStateToProps(state) {
    	return { toDos: state };
    }
    
    function mapDispatchToProps(dispatch) {
    	return {
    		addToDo: (text) => {
    			dispatch(actionCreators.addToDo(text));
    		}
    	};
    }
    
    export default connect(mapStateToProps, mapDispatchToProps)(Home);
  2. store.js

    import { createStore } from 'redux';
    
    const ADD = 'ADD';
    const DELETE = 'DELETE';
    
    const addToDo = (text) => {
    	return {
    		type: ADD,
    		text
    	};
    };
    
    const deleteToDo = (id) => {
    	return {
    		type: DELETE,
    		id
    	};
    };
    
    const reducer = (state = [], action) => {
    	switch (action.type) {
    		case ADD:
    			return [{ text: action.text, id: Date.now() }, ...state];
    		case DELETE:
    			return state.filter((toDo) => toDo !== action.id);
    		default:
    			return state;
    	}
    };
    const store = createStore(reducer);
    
    export const actionCreators = {
    	addToDo,
    	deleteToDo
    };
    
    export default store;

3.4 Deleting To Do


  1. toDo.js 생성

    import React from 'react';
    import { connect } from 'react-redux';
    import { actionCreators } from '../store';
    
    function ToDo({ text, onBtnClick }) {
    	return (
    		<li>
    			{text} <button onClick={onBtnClick}>DEL</button>
    		</li>
    	);
    }
    
    function mapDispatchToProps(dispatch, ownProps) {
    	return {
    		onBtnClick: () => dispatch(actionCreators.deleteToDo(ownProps.id))
    	};
    }
    
    export default connect(null, mapDispatchToProps)(ToDo);
  2. store.js 수정

    import { createStore } from 'redux';
    
    const ADD = 'ADD';
    const DELETE = 'DELETE';
    
    const addToDo = (text) => {
    	return {
    		type: ADD,
    		text
    	};
    };
    
    const deleteToDo = (id) => {
    	return {
    		type: DELETE,
    		id: parseInt(id)
    	};
    };
    
    const reducer = (state = [], action) => {
    	switch (action.type) {
    		case ADD:
    			return [{ text: action.text, id: Date.now() }, ...state];
    		case DELETE:
    			return state.filter((toDo) => toDo.id !== action.id);
    		default:
    			return state;
    	}
    };
    const store = createStore(reducer);
    
    export const actionCreators = {
    	addToDo,
    	deleteToDo
    };
    
    export default store;
  3. Home.js 수정

    import React, { useState } from 'react';
    import { connect } from 'react-redux';
    import { actionCreators } from '../store';
    import ToDo from '../components/ToDo';
    
    function Home({ toDos, addToDo }) {
    	const [text, setText] = useState('');
    	function onChange(e) {
    		setText(e.target.value);
    	}
    	function onSubmit(e) {
    		e.preventDefault();
    		addToDo(text);
    		setText('');
    	}
    	return (
    		<>
    			<h1>To Do</h1>
    			<form onSubmit={onSubmit}>
    				<input type='text' value={text} onChange={onChange} />
    				<button>Add</button>
    			</form>
    			<ul>
    				{toDos.map((toDo) => (
    					<ToDo {...toDo} key={toDo.id} />
    				))}
    			</ul>
    		</>
    	);
    }
    
    function mapStateToProps(state) {
    	return { toDos: state };
    }
    
    function mapDispatchToProps(dispatch) {
    	return {
    		addToDo: (text) => {
    			dispatch(actionCreators.addToDo(text));
    		}
    	};
    }
    
    export default connect(mapStateToProps, mapDispatchToProps)(Home);

3.5 Detail Screen


  1. ToDo.js 수정

    import React from 'react';
    import { connect } from 'react-redux';
    import { Link } from 'react-router-dom';
    import { actionCreators } from '../store';
    
    function ToDo({ text, onBtnClick, id }) {
    	return (
    		<li>
    			<Link to={`/${id}`}>
    				{text} <button onClick={onBtnClick}>DEL</button>
    			</Link>
    		</li>
    	);
    }
    
    function mapDispatchToProps(dispatch, ownProps) {
    	return {
    		onBtnClick: () => dispatch(actionCreators.deleteToDo(ownProps.id))
    	};
    }
    
    export default connect(null, mapDispatchToProps)(ToDo);
  2. Detail.js 수정

    import React from 'react';
    import { useParams } from 'react-router-dom';
    import { connect } from 'react-redux';
    
    function Detail({ toDo }) {
    	return (
    		<>
    			<h1>{toDo?.text}</h1>
    			<h5>Created at: {toDo?.id}</h5>
    		</>
    	);
    }
    
    function mapStateToProps(state, ownProps) {
    	const {
    		match: {
    			params: { id }
    		}
    	} = ownProps;
    	return { toDo: state.find((toDo) => toDo.id === parseInt(id)) };
    }
    
    export default connect(mapStateToProps)(Detail);

3.6 Conclusions


💪 Challenge

  • ToDos를 local storage에 저장해보자 & 변화마다 갱신 필요
profile
프론트엔드 / 컴퓨터공학과 4학년

0개의 댓글