Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

React question(route component doesn't work in <Switch>)

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.

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

  1. make javascript file.
import React from 'react'

function Test() {
  
  return (
    <div>
      test page
    </div>
  )
}

export default Test;
  1. import in the App.js
import Cart from './Cart.js';
  1. 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>
Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading