I used <Switch> component, and some <Route> are working.
To use Route, I made .js file and export, import to use in App.js
<Switch>
<Route path="/detail">
<Detail></Detail>
</Route>
<Route path="/detail">
<Detail></Detail>
</Route>
<Route path="/cart">
<Cart></Cart>
</Route>
</Switch>
However, I can see white page on http://localhost:3000/cart
Cart component doesn’t work.
When I put Cart component out of the Switch component, it works.
I did 3 steps to make and use component.
- make javascript file.
import React from 'react'
function Test() {
return (
<div>
test page
</div>
)
}
export default Test;
- import in the App.js
import Cart from './Cart.js';
- use component in the App.js
<Route path="/cart">
<Test></Test>
</Route>
The main problem is that some Route component doesn’t work in Switch component.
Is there anything wrong or something to note?
Sorry for not explaining better.
==================================================================
This is the code I’m practicing right now, so it may be hard to see.
the actual codes are
App.js
import React, { useContext, useState } from 'react';
import { Navbar, Container, Nav, NavDropdown, Button } from 'react-bootstrap';
import './App.css';
import Data from './data.js';
import Detail from './Detail.js';
import axios from 'axios';
import Cart from './Cart.js';
import Test from './Test.js';
import { Link, Route, Switch } from 'react-router-dom';
// context๋ง๋ค๊ธฐ
// 1. React.createContext(); ๋ก ๋ฒ์ ์์ฑ
// 2. ๊ฐ์ ๊ฐ์ ๊ณต์ ํ HTML์ ๋ฒ์๋ก ์ธ๋งค๊ธฐ
// 3. useContext(๋ฒ์์ด๋ฆ)๋ก ๊ณต์ ๋ ๊ฐ ์ฌ์ฉํ๊ธฐ
export let stockContext = React.createContext();
function App() {
let [shoes, setShoes] = useState(Data);
let [stock, setStock] = useState([10, 11, 12])
return (
<div className="App">
<Navbar bg="light" expand="lg">
<Container>
<Navbar.Brand href="#home">ShoeShop</Navbar.Brand>
<Navbar.Toggle aria-controls="basic-navbar-nav" />
<Navbar.Collapse id="basic-navbar-nav">
<Nav className="me-auto">
<Nav.Link as={Link} to="/">Home</Nav.Link>
<Nav.Link as={Link} to="/detail/0">Detail</Nav.Link>
<Nav.Link as={Link} to="/cart/">Cart</Nav.Link>
<Nav.Link as={Link} to="/test/">Test</Nav.Link>
<NavDropdown title="Dropdown" id="basic-nav-dropdown">
<NavDropdown.Item href="#action/3.1">Action</NavDropdown.Item>
<NavDropdown.Item href="#action/3.2">Another action</NavDropdown.Item>
<NavDropdown.Item href="#action/3.3">Something</NavDropdown.Item>
<NavDropdown.Divider />
<NavDropdown.Item href="#action/3.4">Separated link</NavDropdown.Item>
</NavDropdown>
</Nav>
</Navbar.Collapse>
</Container>
</Navbar>
<Switch>
<Route exact path="/">
<div className="background">
<h1>20% Season Off</h1>
<p>
This is a simple example.
</p>
<p>
<Button variant="primary">Learn more</Button>
</p>
</div>
<div className="container">
<stockContext.Provider value={stock}>
<div className="row">
{
shoes.map( (a, i)=>{
return <Card shoes={shoes[i]} i={i}></Card>
})
}
</div>
</stockContext.Provider>
<button className="btn btn-primary" onClick={()=>{
// ์๋ฒ๋ก ๋ฐ์ดํฐ ๋ณด๋ด๊ณ ์ถ์๋
// axios.post('์๋ฒurl', {id : 'jino', pw : 1234})
// ์๋ฒUrl์ get์์ฒญ
axios.get('https://codingapple1.github.io/shop/data2.json')
// ์ฑ๊ณตํ๋ฉด
.then((result)=>{
setShoes([...shoes, ...result.data]);
})
// ์คํจํ๋ฉด
.catch(()=>{
console.log('์คํจ')
})
}}>๋๋ณด๊ธฐ</button>
</div>
</Route>
<stockContext.Provider value={stock}>
<Route path="/detail/:id">
<Detail shoes={shoes} stock={stock} setStock={setStock}></Detail>
</Route>
</stockContext.Provider>
<Route path="/cart">
<Cart></Cart>
</Route>
<Route path="/test">
<Test></Test>
</Route>
{/* ๋ชจ๋ ๊ฒฝ๋ก์์ ๋ณด์ธ๋ค. ์ง๊ธ์ Switch ์ปดํฌ๋ํธ ์์์์ด์ Router๋ค์ด ํ๋๋ง๋ณด์ธ๋ค. */}
{/* <Route path="/:id">
<div>์๋ฌด๊ฑฐ๋ ์ ์์๋ ์ด๊ฒ์ด ๋ณด์ธ๋ค.</div>
</Route> */}
</Switch>
</div>
);
}
function Card(props){
return(
<div className="col-md-4">
<img src={"https://codingapple1.github.io/shop/shoes"+ (props.i+1) +".jpg"} width="100%" />
<h4>{props.shoes.title}</h4>
<p>{props.shoes.content} & {props.shoes.price}</p>
{/* <Test></Test> */}
</div>
)
}
// function Test(){
// let stock = useContext(stockContext);
// return <p>์ฌ๊ณ : {stock}</p>
// }
export default App;
Cart.js
import Recact from 'react';
import {Table} from 'react-bootstrap';
function Cart(){
return (
<div>
<Table striped bordered hover>
<thead>
<tr>
<th>#</th>
<th>First Name</th>
<th>Last Name</th>
<th>Username</th>
</tr>
</thead>
<tbody>
<tr>
<td>1</td>
<td>Mark</td>
<td>Otto</td>
<td>@mdo</td>
</tr>
<tr>
<td>2</td>
<td>Jacob</td>
<td>Thornton</td>
<td>@fat</td>
</tr>
<tr>
<td>3</td>
<td colSpan={2}>Larry the Bird</td>
<td>@twitter</td>
</tr>
</tbody>
</Table>
</div>
)
}
export default Cart;
import React, { useContext, useEffect, useState } from 'react';
import { useHistory, useParams } from 'react-router-dom';
import './Detail.scss';
import {Button, Nav} from 'react-bootstrap';
import {CSSTransition} from 'react-transition-group';
import {stockContext} from './App'
function Detail(props){
let [alert, setAlert] = useState(true);
let stock = useContext(stockContext);
let [tab, setTab] = useState(0);
let [buttonSwitch, setButtonSwitch] = useState(false);
// useEffect ํ
: ์ปดํฌ๋ํธ๊ฐ mount๋์์๋, update๋ ๋ ํน์ ์ฝ๋๋ฅผ ์คํํ ์ ์๋ค.
// useEffect ์ฌ๋ฌ๊ฐ ์ฌ์ฉํ๋ฉด ์์๋๋ก ์คํ
useEffect(()=>{
let timer = setTimeout(()=>{ setAlert(false) }, 2000);
// 2000ms ํ์ ์คํํ ์ฝ๋
// retrun(Detail ์ปดํฌ๋ํธ๊ฐ ์ฌ๋ผ์ง๋ ์คํ)
// return function code(){}
// return ()=>(){} ์ ๊ฐ์
// ์๋์น ์์ error๊ฐ ๋ฐ์ํ ์ ์์ด clearTimeout() ํจ์ ์ฌ์ฉ
return ()=> {clearTimeout(timer)}
},[alert]);
// [] ์์ useEffect๊ฐ ์คํ๋ ์กฐ๊ฑด ์
๋ ฅ / ์ฌ๊ธฐ์ alert๊ฐ ๋ณ๊ฒฝ๋ ๋๋ง ์คํํ๋ค.
// ๋น[] ๋ฉด update์์ ์ ์ฉํ์ง์๋๋ค.
let { id } = useParams();
let history = useHistory();
let product = props.shoes.find(function(shoes){
return shoes.id == id;
});
return (
<div className="container">
<div>
<p className="red">Detail</p>
</div>
{/* alert๊ฐ true์ธ์ง ?? // ?-> ์ฐธ์ผ๋ ์คํํ ์ฝ๋ / : -> ๊ฑฐ์ง์ผ๋ ์คํํ ์ฝ๋ */}
{
alert === true
? (<div className="my-alert">
<p>์ฌ๊ณ ๊ฐ ์ผ๋ง ๋จ์ง ์์์ต๋๋ค.</p>
</div>)
: null
}
<div className="row">
<div className="col-md-6">
<img src={"https://codingapple1.github.io/shop/shoes"+(product.id+1)+".jpg"} width="100%" />
</div>
<div className="col-md-6 mt-4">
<h4 className="pt-5">{product.title}</h4>
<p>{product.content}</p>
<p>{product.price}์</p>
<Info stock={props.stock}></Info>
<button className="btn btn-danger" onClick={()=>{
var copyArray = [...props.stock];
copyArray[0] -= 1;
props.setStock(copyArray);
}}>์ฃผ๋ฌธํ๊ธฐ</button>
<button className="btn btn-danger" onClick={()=>{
// history.goBack();
history.push('/')
}}>๋ค๋ก๊ฐ๊ธฐ</button>
</div>
</div>
<Nav className="mt-t" variant="tabs" defaultActiveKey="link-0">
<Nav.Item>
<Nav.Link eventKey="link-0" onClick={()=>{
setButtonSwitch(false);
setTab(0);
}}>0๋ฒ์งธ ํญ</Nav.Link>
</Nav.Item>
<Nav.Item>
<Nav.Link eventKey="link-1" onClick={()=>{
setButtonSwitch(false);
setTab(1)
}}>1๋ฒ์งธ ํญ</Nav.Link>
</Nav.Item>
<Nav.Item>
<Nav.Link eventKey="link-2" onClick={()=>{
setButtonSwitch(false);
setTab(2)
}}>2๋ฒ์งธ ํญ</Nav.Link>
</Nav.Item>
</Nav>
{/* ์ค์์น(true๋ฉด ๋์) ๋์ํ๋ ์๊ฐ*/}
<CSSTransition in={buttonSwitch} classNames="wow" timeout={500}>
<TabContent tab={tab} setButtonSwitch={setButtonSwitch}></TabContent>
</CSSTransition>
</div>
)
}
function Info(props){
return (
<p>์ฌ๊ณ : {props.stock[0]}</p>
)
}
// ์กฐ๊ฑด์ด 3๊ฐ์ด์์ธ ์กฐ๊ฑด๋ฌธ๋ง๋ค๊ธฐ
function TabContent(props) {
useEffect(()=>{
props.setButtonSwitch(true);
});
if(props.tab===0){
return <div>0๋ฒ์งธ ๋ด์ฉ์
๋๋ค.</div>
} else if(props.tab===1){
return <div>1๋ฒ์งธ ๋ด์ฉ์
๋๋ค.</div>
} else if (props.tab===2){
return <div>2๋ฒ์งธ ๋ด์ฉ์
๋๋ค.</div>
}
}
export default Detail;
Test.js
import React from 'react'
function Test() {
return (
<div>
test page
</div>
)
}
export default Test;
>Solution :
Issue
The issue is the stockContext.Provider component in the middle of the Switch component. It will always be "matched" and rendered if a route above wasn’t, and the route matching logic won’t ever reach the routes defined after it.
<Switch>
<Route exact path="/">
...
</Route>
// Will be matched and rendered if route above not matched
<stockContext.Provider value={stock}>
<Route path="/detail/:id">
<Detail shoes={shoes} stock={stock} setStock={setStock}></Detail>
</Route>
</stockContext.Provider>
// Unreachable routes!!
<Route path="/cart">
<Cart></Cart>
</Route>
<Route path="/test">
<Test></Test>
</Route>
{/* ๋ชจ๋ ๊ฒฝ๋ก์์ ๋ณด์ธ๋ค. ์ง๊ธ์ Switch ์ปดํฌ๋ํธ ์์์์ด์ Router๋ค์ด ํ๋๋ง๋ณด์ธ๋ค. */}
{/* <Route path="/:id">
<div>์๋ฌด๊ฑฐ๋ ์ ์์๋ ์ด๊ฒ์ด ๋ณด์ธ๋ค.</div>
</Route> */}
</Switch>
Solution
Move the stockContext.Provider out of the Switch component, or into the Route so the Route is a child of Switch component.
Example:
<stockContext.Provider value={stock}>
<Switch>
<Route exact path="/">
...
</Route>
<Route path="/detail/:id">
<Detail shoes={shoes} stock={stock} setStock={setStock} />
</Route>
<Route path="/cart">
<Cart />
</Route>
<Route path="/test">
<Test />
</Route>
{/* ๋ชจ๋ ๊ฒฝ๋ก์์ ๋ณด์ธ๋ค. ์ง๊ธ์ Switch ์ปดํฌ๋ํธ ์์์์ด์ Router๋ค์ด ํ๋๋ง๋ณด์ธ๋ค. */}
{/* <Route path="/:id">
<div>์๋ฌด๊ฑฐ๋ ์ ์์๋ ์ด๊ฒ์ด ๋ณด์ธ๋ค.</div>
</Route> */}
</Switch>
</stockContext.Provider>
or
<Switch>
<Route exact path="/">
...
</Route>
<Route path="/detail/:id">
<stockContext.Provider value={stock}>
<Detail shoes={shoes} stock={stock} setStock={setStock} />
</stockContext.Provider>
</Route>
<Route path="/cart">
<Cart />
</Route>
<Route path="/test">
<Test />
</Route>
{/* ๋ชจ๋ ๊ฒฝ๋ก์์ ๋ณด์ธ๋ค. ์ง๊ธ์ Switch ์ปดํฌ๋ํธ ์์์์ด์ Router๋ค์ด ํ๋๋ง๋ณด์ธ๋ค. */}
{/* <Route path="/:id">
<div>์๋ฌด๊ฑฐ๋ ์ ์์๋ ์ด๊ฒ์ด ๋ณด์ธ๋ค.</div>
</Route> */}
</Switch>