5버전과 6버전의 차이
// index.js에 추가
import { BrowserRouter } from 'react-router-dom'
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<BrowserRouter>
<App />
</BrowserRouter>
);
index.js
에 <BrowserRouter>
를 추가하고 사용하면 된다.
function App() {
return (
<div>
<Link to="/">Main</Link>
<Link to="posts">Posts</Link>
<Routes>
// 5버전에서는 '/'라는 라우트, '/posts'라는 라우트에 '/'가 중복되면서 중첩적으로 요소가 모두 보이는 현상이 있었다.
// 그래서 exact라는 옵션으로 완전 일치했을때만 요소가 나타나도록했다.
// 6버전에서는 exact가 모두 적용이 되어있게 됐다.
<Route path="posts" element={ <Posts /> }></Route>
<Route path="users" element={ <Users /> }></Route>
</Routes>
</div>
);
}
<Link>
는 a태그와 같다. <Routes>
영역은 URL주소에 따라서 보여지는 부분이다. <Route>
는 그 안에서 어떤 주소일때 무엇을 보여줄지 정의할 수 있다.
<Routes>
는 주소 변경을 감지해서 <Route>
중에서 일치하는 주소를 찾아 보여주는 역할을 한다.
<Route path="*" element={ <p>Not Found</p> }></Route>
해당하는 주소가 없을때에는 *
경로로 사용자에게 잘못됨을 알려준다.
<Route path="posts" element={ <Posts /> }>
<Route path=":postId" element={ <PostDetail /> }></Route>
</Route>
:postId
에 콜론이 붙어있는 의미는 변수로서 받아들인다는 뜻이다. 그래서 posts/1
로 주소 이동하면 PostDetail 컴포넌트가 나타난다.
import { Outlet } from 'react-router-dom'
function Posts() {
return (
<div>
<Outlet />
</div>
)
}
그렇다면 하위 컴포넌트 PostDetail은 어디서 표시되야 할까. 상위 컴포넌트 <Outlet />
위치에 표시된다. 이렇듯 계층적인 구조가 된다면 부모 라우트에는 항상 <Outlet />
이 들어있어야 한다.
계층적인 구조보다 주소만 상세히 들어가고 페이지는 완전 전환이 되고싶다 하면 서로 연결되지 않도록 따로 구성을 해줘야한다.
<Route path="posts" element={ <Posts /> }></Route> <Route path="posts/:postId" element={ <PostDetail /> }></Route>
하지만 기본적으로는 계층적으로 구성하는게 더 좋은 설계 방식이다.
<Route path="posts" element={ <Posts /> }>
<Route index element={ <PostIndex /> }></Route>
<Route path=":postId" element={ <PostDetail /> }></Route>
</Route>
index는 주소 posts로 들어갔을때 보여줄 기본 요소를 보여준다. 부모 라우트 컴포넌트에는 navBar 등 공통적인 요소를 넣고, index에는 posts의 첫화면에 보여질 메인 화면같은 요소를 넣어주는걸로 활용된다.
URL path에 명시된 파라미터 값을 받아올 수 있다.(주소창에 있는 값)
import { useParams } from 'react-router-dom'
function PostDetail() {
const params = useParams()
return (
<div>{params.postId}</div>
)
}
무언가를 검색할때 URL에 검색 조건을 달아서 검색을 한다. 그럴때 posts?title=lemon
주소에 이런 형태가 남게된다.
function PostIndex() {
const [searchParams, setSearchParams] = useSearchParams()
const [posts, setPosts] = useState(postData)
// 사용자 검색어 입력
const searchInputHandler = (e) => {
const filter = e.target.value;
filter ? setSearchParams({filter}) : setSearchParams({})
}
// 사용자가 검색어를 입력했는지 감시중
useEffect(() => {
setPosts(postData.filter(post => {
// 주소에 검색어가 postData에 있니?
const filter = searchParams.get("filter")
const title = post.title.toLowerCase()
return filter ? title.includes(filter) : true
}))
}, [searchParams])
return (
<div>
<input onChange={searchInputHandler} />
// useState인 posts가 변경되면 다시 map이 실행됨
<p>{posts.map(post => (<Link to={`/posts/${post.id}`}><p>{post.title}</p></Link>))}</p>
</div>
)
}
현재 URL위치를 알려준다. 알 수 있는 값중에 state를 가장 많이 쓴다.