spartacoding (프론트엔드의 꽃, 리액트) - 3주차
리액트에서 라우팅 처리하기
react-route-dom 설치
yarn add react-router-dom
현재 어느 주소를 보고 있는 지 쉽게 알려주는 BrowserRouter
index.js
import React from 'react';
import ReactDOM from "react-dom";
import { BrowserRouter } from "react-router-dom";
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
// 이부분이 index.html에 있는 div#root에 우리가 만든 컴포넌트를 실제로 랜더링하도록 연결해주는 부분입니다.
ReactDOM.render(
<BrowserRouter>
<App />
</BrowserRouter>,
document.getElementById("root")
);
// 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();
세부 화면 만들기
Home.js
import React from 'react';
const Home = (props) => {
return (<div>메인 화면이에요.</div>);
};
export default Home;
Cat.js
import React from "react";
const Cat = (props) => {
console.log(props.match);
return (
<div>고양이 화면이에요.</div>
)
}
export default Cat;
Dog.js
import React from 'react';
const Dog = (props) => {
return (<div>강아지 화면이에요.</div>);
};
export default Dog;
App.js에서 Route 적용하기
1: 넘겨줄 props가 없을 때
<Route path="주소[/home 처럼 /와 주소를 적어요]" component={[보여줄 컴포넌트]}/>
2: 넘겨줄 props가 있을 때
<Route path="주소[/home 처럼 /와 주소를 적어요]" render={(props) => ()} />
App.js에 적용해보기
import React from 'react';
import './App.css';
import {withRouter} from "react-router";
import { Route, Link } from "react-router-dom";
import Home from "./Home";
import Cat from "./Cat";
import Dog from "./Dog";
class App extends React.Component {
constructor(props){
super(props);
this.state={};
}
componentDidMount() {
}
render(){
return (
<div className="App">
<div>
<Link to="/">Home으로 가기</Link>
<Link to="/cat">Cat으로 가기</Link>
<Link to="/dog">Dog으로 가기</Link>
</div>
<hr />
{/* 실제로 연결해볼까요! */}
<Route path="/" exact component={Home} />
<Route path="/cat" component={Cat} />
<Route path="/dog" component={Dog} />
<button onClick={() => {
this.props.history.push('/cat/nabi');
}}>/cat으로 가기</button>
<button onClick={() => {
this.props.history.goBack();
}}>뒤로가기</button>
</div>
);
}
}
export default withRouter(App);
exact를 추가하면 /를 입력했을 때 Home 컴포넌트만 뜰 수 있음
파라미터 주기
<Route path="/cat/:cat_name" component={Cat}/>
파라미터 사용 방법
import React from 'react';
const Cat = (props) => {
console.log(props.match);
return ( <div>고양이 화면이에요.</div> )
}
export default Cat;
<Link/>사용 방법> <Link to="주소">[텍스트]</Link>
history 객체를 props로 받아오려면, withRouter를 설정해줘야 합니다.
버킷리스트 상세 페이지 만들고 이동시키기
index.js
import React from 'react';
import ReactDOM from "react-dom";
import { BrowserRouter } from "react-router-dom";
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
// 이부분이 index.html에 있는 div#root에 우리가 만든 컴포넌트를 실제로 랜더링하도록 연결해주는 부분입니다.
ReactDOM.render(
<BrowserRouter>
<App />
</BrowserRouter>,
document.getElementById("root")
);
// 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();
App.js
import React from "react";
import { withRouter } from "react-router";
import { Route, Switch } from "react-router-dom";
// import [컴포넌트 명] from [컴포넌트가 있는 파일경로];
import BucketList from "./BucketList";
import styled from "styled-components";
import Detail from "./Detail";
import NotFound from './NotFound';
// 클래스형 컴포넌트는 이렇게 생겼습니다!
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
list: ["영화관 가기", "매일 책읽기", "수영 배우기"],
};
this.text = React.createRef();
}
componentDidMount() {
console.log(this.text);
}
addBucketList = () => {
let list = this.state.list;
const new_item = this.text.current.value;
this.setState({ list: [...list, new_item] });
};
render() {
return (
<div className="App">
<Container>
<Title>내 버킷리스트</Title>
<Line />
<Switch>
<Route
path="/"
exact
render={(props) => <BucketList list={this.state.list} history={this.props.history}/>}
/>
<Route path="/detail" component={Detail}/>
<Route component={NotFound}/>
<Route render={(props) => {
<NotFound history={this.props.history}/>
}}/>
</Switch>
</Container>
<Input>
<input type="text" ref={this.text} />
<button onClick={this.addBucketList}>추가하기</button>
</Input>
</div>
);
}
}
const Input = styled.div`
max-width: 350px;
min-height: 10vh;
background-color: #fff;
padding: 16px;
margin: 20px auto;
border-radius: 5px;
border: 1px solid #ddd;
`;
const Container = styled.div`
max-width: 350px;
min-height: 60vh;
background-color: #fff;
padding: 16px;
margin: 20px auto;
border-radius: 5px;
border: 1px solid #ddd;
`;
const Title = styled.h1`
color: slateblue;
text-align: center;
`;
const Line = styled.hr`
margin: 16px 0px;
border: 1px dotted #ddd;
`;
export default withRouter(App);
BucketList.js
import React from "react";
import styled from "styled-components";
const BucketList = (props) => {
console.log(props);
const my_lists = props.list;
return (
<ListStyle>
{my_lists.map((list, index) => {
return (
<ItemStyle className="list_item" key={index} onClick={() => {
props.history.push('/detail');
}}>
{list}
</ItemStyle>
);
})}
</ListStyle>
);
};
const ListStyle = styled.div`
display: flex;
flex-direction: column;
height: 100%;
overflow-x: hidden;
overflow-y: auto;
`;
const ItemStyle = styled.div`
padding: 16px;
margin: 8px;
background-color: aliceblue;
`;
export default BucketList;
Detail.js
import React from 'react';
const Detail = (props) => {
return <h1>상세 페이지입니다!</h1>;
};
export default Detail;
NotFound.js
import React from 'react';
const NotFound = (props) => {
return (
<div>
<h1>주소가 올바르지 않아요!</h1>
<button onClick={() => {props.history.goBack();}}>뒤로가기</button>
</div>
);
};
export default NotFound;
리덕스 써보기
리덕스 패키지 설치하기
yarn add redux react-redux
모듈 만들기
bucket.js
// bucket.js
// Actions
const LOAD = "bucket/LOAD";
const CREATE = "bucket/CREATE";
const initialState = {
list: ["영화관 가기", "매일 책읽기", "수영 배우기"],
};
// Action Creators
export const loadBucket = (bucket) => {
return { type: LOAD, bucket };
}
export const createBucket = (bucket) => {
return { type: CREATE, bucket };
}
// Reducer
export default function reducer(state = initialState, action = {}) {
switch (action.type) {
case "bucket/LOAD": {
return state;
}
case "bucket/CREATE": {
const new_bucket_list = [...state.list, action.bucket];
return {list: new_bucket_list};
break;
}
// do reducer stuff
default: return state;
}
}
configStore.js
import {createStore, combineReducers} from "redux";
import bucket from './modules/bucket';
import { createBrowserHistory } from "history";
export const history = createBrowserHistory();
const rootReducer = combineReducers({bucket});
const store = createStore(rootReducer);
export default store;
리덕스와 컴포넌트 연결하기
index.js
import React from 'react';
import ReactDOM from "react-dom";
import { BrowserRouter } from "react-router-dom";
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
import {Provider} from 'react-redux';
import store from './redux/configStore';
// 이부분이 index.html에 있는 div#root에 우리가 만든 컴포넌트를 실제로 랜더링하도록 연결해주는 부분입니다.
ReactDOM.render(
<Provider store={store}>
<BrowserRouter>
<App />
</BrowserRouter>
</Provider>,
document.getElementById("root")
);
// 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();
컴포넌트에서 리덕스 데이터 사용하기
App.js
import React from "react";
import { withRouter } from "react-router";
import { Route, Switch } from "react-router-dom";
// import [컴포넌트 명] from [컴포넌트가 있는 파일경로];
import BucketList from "./BucketList";
import styled from "styled-components";
import Detail from "./Detail";
import NotFound from './NotFound';
import {connect} from 'react-redux';
import { loadBucket, createBucket } from "./redux/modules/bucket";
const mapStateToProps = (state) => {
return {bucket_list: state.bucket.list};
}
const mapDispatchToProps = (dispatch) => {
return {
load: () => {
dispatch(loadBucket());
},
create: (bucket) => {
dispatch(createBucket(bucket));
}
};
}
// 클래스형 컴포넌트는 이렇게 생겼습니다!
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
};
this.text = React.createRef();
}
componentDidMount() {
console.log(this.text);
}
addBucketList = () => {
const new_item = this.text.current.value;
this.props.create(new_item);
};
render() {
return (
<div className="App">
<Container>
<Title>내 버킷리스트</Title>
<Line />
<Switch>
<Route
path="/"
exact
render={(props) => <BucketList list={this.props.bucket_list} history={this.props.history}/>}
/>
<Route path="/detail/:index" component={Detail}/>
<Route component={NotFound} render={(props) => {
<NotFound history={this.props.history}/>
}}/>
</Switch>
</Container>
<Input>
<input type="text" ref={this.text} />
<button onClick={this.addBucketList}>추가하기</button>
</Input>
</div>
);
}
}
const Input = styled.div`
max-width: 350px;
min-height: 10vh;
background-color: #fff;
padding: 16px;
margin: 20px auto;
border-radius: 5px;
border: 1px solid #ddd;
`;
const Container = styled.div`
max-width: 350px;
min-height: 60vh;
background-color: #fff;
padding: 16px;
margin: 20px auto;
border-radius: 5px;
border: 1px solid #ddd;
`;
const Title = styled.h1`
color: slateblue;
text-align: center;
`;
const Line = styled.hr`
margin: 16px 0px;
border: 1px dotted #ddd;
`;
export default connect(mapStateToProps, mapDispatchToProps)(withRouter(App));
BucketList.js
import React from "react";
import styled from "styled-components";
import { useSelector, useDispatch } from "react-redux";
const BucketList = (props) => {
const bucket_list = useSelector(state => state.bucket.list);
return (
<ListStyle>
{bucket_list.map((list, index) => {
return (
<ItemStyle className="list_item" key={index} onClick={() => {
props.history.push('/detail/' + index);
}}>
{list}
</ItemStyle>
);
})}
</ListStyle>
);
};
const ListStyle = styled.div`
display: flex;
flex-direction: column;
height: 100%;
overflow-x: hidden;
overflow-y: auto;
`;
const ItemStyle = styled.div`
padding: 16px;
margin: 8px;
background-color: aliceblue;
`;
export default BucketList;
Detail.js
import React from 'react';
import { useSelector, useDispatch } from 'react-redux';
const Detail = (props) => {
const bucket_list = useSelector((state) => state.bucket.list);
console.log(bucket_list, props);
const bucket_index = parseInt(props.match.params.index);
return <h1>{bucket_list[bucket_index]}</h1>;
};
export default Detail;
버킷 리스트 데이터를 삭제해보기
Detail.js
// 리액트 패키지를 불러옵니다.
import React from "react";
// redux hook을 불러옵니다.
import { useDispatch, useSelector } from "react-redux";
// 내가 만든 액션 생성 함수를 불러옵니다.
import {deleteBucket} from "./redux/modules/bucket";
const Detail = (props) => {
const dispatch = useDispatch();
// 스토어에서 상태값 가져오기
const bucket_list = useSelector((state) => state.bucket.list);
// url 파라미터에서 인덱스 가져오기
let bucket_index = parseInt(props.match.params.index);
console.log(props);
return (
<div>
<h1>{bucket_list[bucket_index]}</h1>
<button onClick={() => {
// dispatch(); <- 괄호안에는 액션 생성 함수가 들어가야겠죠?
// 예를 들면 이렇게요.
dispatch(deleteBucket(bucket_index));
props.history.goBack();
}}>삭제하기</button>
</div>
);
};
export default Detail;
bucketList.js
// widgets.js
// Actions
const LOAD = "bucket/LOAD";
const CREATE = "bucket/CREATE";
const DELETE = "bucket/DELETE";
const initialState = {
list: ["영화관 가기", "매일 책읽기", "수영 배우기"],
};
// Action Creators
export const loadBucket = (bucket) => {
return { type: LOAD, bucket };
};
export const createBucket = (bucket) => {
return { type: CREATE, bucket };
};
export const deleteBucket = (bucket) => {
return { type: DELETE, bucket };
};
// Reducer
export default function reducer(state = initialState, action) {
console.log(action);
switch (action.type) {
// do reducer stuff
case "bucket/LOAD":
return state;
case "bucket/CREATE":
console.log(state, action);
const new_bucket_list = [...state.list, action.bucket];
return { list: new_bucket_list };
case "bucket/DELETE":
const bucket_list = state.list.filter((l, idx) => {
if(idx !== action.bucket){
return l;
}
});
return {list: bucket_list};
default:
return state;
}
}
Author And Source
이 문제에 관하여(spartacoding (프론트엔드의 꽃, 리액트) - 3주차), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@star5013/spartacoding-프론트엔드의-꽃-리액트-3주차저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)