– prerequite
sub menu – 네스티드 라우팅
heroes 메뉴 아래에 리스트보기와 등록 페이지를 포함하는 Index 페이지를 만들자. 여기에는 목록보기와 등록페이지 링크를 포함하는 sub menu 를 포함한다.
heroes 페이지폴더 아래에 Register.js 컴포넌트를 추가한다. 이 페이지는 나중에 hero 등록페이지로 만들것이다.
1 2 3 4 5 6 7 |
export const Register = (props) => { return ( <div> Register works!! </div> ) } |
목록보기와 등록페이지를 모두 포함하는부모페이지인 Index 페이지를 추가한다. 상단에 메뉴바가 들어가고 바로 아래에 Route가 위치한다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
import React from 'react'; import {NavItem, Nav} from "reactstrap"; import {NavLink, Switch, Route} from "react-router-dom"; import {Heroes} from "./Heroes"; import {Register} from "./Register"; import './Index.scss'; export const Index = (props) => { return ( <> <Nav className="mb-3"> <NavItem> <NavLink to="/heroes/hero" className="nav-link">Hero List</NavLink> </NavItem> <NavItem> <NavLink to="/heroes/register" className="nav-link">Register</NavLink> </NavItem> </Nav> <Switch> <Route path="/heroes/hero" component={Heroes}></Route> <Route path="/heroes/register" component={Register}></Route> </Switch> </> ) } |
위에서 추가된 Index.scss는 아래와 같다.
상단 메뉴에 active 클래스를 선택된 영역으로 진하게하는 scss를 추가한다.
1 2 3 4 5 6 7 8 9 |
.nav-link { color: #666666; &:hover{ color: #333333; } &.active { font-weight: bold; } } |
Root.js 에는 /heroes 경로를 Heroes가 아니라 Index로 바꿔줘야 한다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
export const Root = (props) => { return ( <BrowserRouter> <Menu></Menu> <div className="container" style={{backgroundColor: '#ffffff'}}> <Switch> <Route exact path="/" component={Home}></Route> <Route path="/heroes" component={Index}></Route> <Route path="/scoreboard" component={Scoreboard}></Route> <Route path="/product" component={Product}></Route> </Switch> </div> </BrowserRouter> ) } |
탑 메뉴에서 heroes 메뉴 선택후 sub 메뉴에서 hero list 와 register를 눌러서 active 가 제대로 표시되는지 확인하자.
sub menu active 처리
heroes 메뉴를 클릭시 아래와 같이 현재 아무 화면도 나오지 않는다.
디폴트로 hero list 를 나오게 할려면 어떻게 해야 할까? 만일 NavLink를 /heroes/hero를 /heroes로 바꾸고 Route 패스를 exact path=”heroes” 로 바꾸면 될거 같은데 그러면 어떤 문제가 있는지 살펴보자.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
<> <Nav className="mb-3"> <NavItem> <NavLink to="/heroes" className="nav-link">Hero List</NavLink> </NavItem> <NavItem> <NavLink to="/heroes/register" className="nav-link">Register</NavLink> </NavItem> </Nav> <Switch> <Route exact path="/heroes" component={Heroes}></Route> <Route path="/heroes/register" component={Register}></Route> </Switch> </> |
테스트해보면 hero list를 진입할때는 문제가 없는데 register로 들어가면 hero list도 같이 active가 되는 현상이 발생한다. 그러므로 이 현상을 수정하기 위해서는 redirect를 사용해야 한다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
import React from 'react'; import {NavItem, Nav} from "reactstrap"; import {NavLink, Switch, Route, Redirect} from "react-router-dom"; import {Heroes} from "./Heroes"; import {Register} from "./Register"; import './Index.scss'; export const Index = (props) => { return ( <> <Nav className="mb-3"> <NavItem> <NavLink to="/heroes/hero" className="nav-link">Hero List</NavLink> </NavItem> <NavItem> <NavLink to="/heroes/register" className="nav-link">Register</NavLink> </NavItem> </Nav> <Switch> <Route path="/heroes/hero" component={Heroes}></Route> <Route path="/heroes/register" component={Register}></Route> <Route path="/heroes" render={() => <Redirect to="/heroes/hero" />} /> </Switch> </> ) } |
register 등록 폼 구성
등록화면을 구성한다. bootstrap의 form-group과 form-control을 사용한다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 |
export const Register = (props) => { return ( <> <h3>Hero Registration</h3> <form> <div className="form-group mt-1"> <label htmlFor="name">Name</label> <input type="text" className="form-control" placeholder="Enter Name" id="name" /> </div> <div className="form-group mt-1"> <label htmlFor="email">Email Address</label> <input type="email" className="form-control" placeholder="Enter Email" id="email" /> </div> <div className="d-flex flex-column mt-1"> <div>성별</div> <div> <div className="form-check form-check-inline"> <input className="form-check-input" type="radio" name="sex" value="male" id="male" /> <label className="form-check-label" htmlFor="male">남자</label> </div> <div className="form-check form-check-inline"> <input className="form-check-input" type="radio" name="sex" value="female" id="female" /> <label className="form-check-label" htmlFor="female">여자</label> </div> </div> </div> <div className="form-group mt-1"> <label htmlFor="country">country</label> <select className="form-control" id="country"> <option value="Japan">Japan</option> <option value="American">American</option> <option value="Korean">Korean</option> </select> </div> <div className="form-group mt-1"> <label htmlFor="address">Address</label> <textarea className="form-control" placeholder="Enter address" id="address" rows="3"></textarea> </div> <div className="d-flex flex-column mt-1"> <div>power</div> <div> <div className="form-check form-check-inline"> <input type="checkbox" className="form-check-input" id="flying" /> <label className="form-check-label" htmlFor="flying">flying</label> </div> <div className="form-check form-check-inline"> <input type="checkbox" className="form-check-input" id="penetration" /> <label className="form-check-label" htmlFor="penetration">penetration</label> </div> <div className="form-check form-check-inline"> <input type="checkbox" className="form-check-input" id="hacking" /> <label className="form-check-label" htmlFor="hacking">hacking</label> </div> <div className="form-check form-check-inline"> <input type="checkbox" className="form-check-input" id="strength" /> <label className="form-check-label" htmlFor="strength">strength</label> </div> </div> </div> <div className="m-3 d-flex justify-content-center"> <button type="submit" className="btn btn-outline-primary">등록</button> </div> </form> </> ) } |
아래와 같은 화면이 된다.
Binding
input, textarea, select box, radio, checkbox 이 다섯가지 html 입력폼 모두를 controlled component로 만들자.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 |
export const Register = (props) => { const [name, setName] = useState(''); const [email, setEmail] = useState(''); const [sex, setSex] = useState({ male: false, female: false }); const [country, setCountry] = useState(''); const [address, setAddress] = useState(''); const [powers, setPowers] = useState({ flying: false, penetration: false, hacking: false, strength: false }); const [photo, setPhoto] = useState(''); return ( <> <h3>Hero Registration</h3> <form> <div className="form-group mt-1"> <label htmlFor="name">Name</label> <input type="text" className="form-control" placeholder="Enter Name" id="name" value={name} onChange={(e) => setName(e.target.value)} /> </div> <div className="form-group mt-1"> <label htmlFor="email">Email Address</label> <input type="email" className="form-control" placeholder="Enter Email" id="email" value={email} onChange={(e) => setEmail(e.target.value)} /> </div> <div className="d-flex flex-column mt-1"> <div>성별</div> <div> <div className="form-check form-check-inline"> <input className="form-check-input" type="radio" name="sex" value="male" id="male" checked={sex.male} onChange={(e) => setSex({male: e.target.checked, female: !e.target.checked})} /> <label className="form-check-label" htmlFor="male">남자</label> </div> <div className="form-check form-check-inline"> <input className="form-check-input" type="radio" name="sex" value="female" id="female" checked={sex.female} onChange={(e) => setSex({male: !e.target.checked, female: e.target.checked})} /> <label className="form-check-label" htmlFor="female">여자</label> </div> </div> </div> <div className="form-group mt-1"> <label htmlFor="country">country</label> <select className="form-control" id="country" value={country} onChange={(e)=>setCountry(e.target.value)} > <option value=""></option> <option value="Japan">Japan</option> <option value="American">American</option> <option value="Korean">Korean</option> </select> </div> <div className="form-group mt-1"> <label htmlFor="address">Address</label> <textarea className="form-control" placeholder="Enter address" id="address" rows="3" value={address} onChange={(e)=>setAddress(e.target.value)}></textarea> </div> <div className="d-flex flex-column mt-1"> <div>powers</div> <div> <div className="form-check form-check-inline"> <input type="checkbox" value="flying" className="form-check-input" id="flying" checked={powers.flying} onChange={(e) => setPowers({...powers, flying: e.target.checked})}/> <label className="form-check-label" htmlFor="flying">flying</label> </div> <div className="form-check form-check-inline"> <input type="checkbox" value="penetration" className="form-check-input" id="penetration" checked={powers.penetration} onChange={(e) => setPowers({...powers, penetration: e.target.checked})} /> <label className="form-check-label" htmlFor="penetration">penetration</label> </div> <div className="form-check form-check-inline"> <input type="checkbox" value="hacking" className="form-check-input" id="hacking" checked={powers.hacking} onChange={(e) => setPowers({...powers, hacking: e.target.checked})}/> <label className="form-check-label" htmlFor="hacking">hacking</label> </div> <div className="form-check form-check-inline"> <input type="checkbox" value="strength" className="form-check-input" id="strength" checked={powers.strength} onChange={(e) => setPowers({...powers, strength: e.target.checked})} /> <label className="form-check-label" htmlFor="strength">strength</label> </div> </div> </div> <div className="m-3 d-flex justify-content-center"> <button type="submit" className="btn btn-outline-primary">등록</button> </div> </form> </> ) } |
디버깅 코드 추가
input 박스에 값을 입력하고, 라디오버튼, 체크박스를 클릭하고 셀렉터박스를 선택시 변경된 값이 제대로 바인딩되는지 확인하기 위해서 form 아래쪽에 바인딩 데이터를 확인할 수 있도록 디버깅 코드를 한줄 추가한다.
1 2 3 4 5 6 7 8 9 10 11 |
... </form> <p> {JSON.stringify({ name, email, sex, country, address, powers, photo })} </p> </> ) } |