본문 바로가기
카테고리 없음

[7주차] 리액트: json의 id 값에 따라 상세페이지로 이동하기 (useParams, Link)

by whereanna00 2023. 11. 15.

리액트 json의 id 값에 따라 상세페이지로 이동하기 (useParams, Link)


Router.js

  • 새 Route 를 만들어주고, path="" 와 element={} 를 넣어준다
  • id 값에 따라서 다른 상세화면을 보여주고 싶으면, path=""상세페이지이름/:id" 를 넣어준다
더보기
//src > shared > Router.js
//Router.js

import React from 'react'
import {BrowserRouter, Routes, Route} from 'react-router-dom';
import Home from '../pages/Home';
import LetterDetails from '../pages/LetterDetails';

function Router() {
  return (
    <BrowserRouter>
      <Routes>
        <Route path="/" element={<Home />}/>
        {/* <Route path="letter-details" element={<LetterDetails />}/> */}
        <Route path="letter-details/:id" element={<LetterDetails />}/>
      </Routes>
    </BrowserRouter>

  )
}

export default Router

 

 

Home.jsx

  • Home 컴포넌트가 반환하는 값에서 letter들이 보여지는 자식 컴포넌트 <List> 는 <Main> 컴포넌트의 자식 컴포넌트이다.
더보기
//src>pages>Home.jsx
//Home.jsx

// Hooks
import React from 'react';
import { useState } from 'react';
import moment from 'moment';
import { useEffect } from 'react';
import { useRef } from 'react';
import { useParams } from 'react-router-dom';
// CSS
import { styled } from 'styled-components';
import GlobalStyle from '../GlobalStyle';
// Components
import Header from '../components/Header';
import Footer from '../components/Footer';
import List from '../components/List';
import Button from '../components/Button';
// import Image from '../components/Image';
// Image
import picturePaul from '../assets/dune-Paul.png';
// Data Fetch
// import fakeData from "../database/fakeData.json";



const Main = styled.div`
  display: flex;
  flex-direction: row;
  justify-content: center;
  align-items: center;
  gap: 60px;
`;

const ImgBtnBox = styled.div`
  display: flex;
  flex-direction: row;
  gap: 60px;
`;

const PicturePaul = styled.img`
  width: 430px;
`;


function Home() {
  const [letterShown, setLetterShown] = useState({
    'Paul' : true,
    'Elio' : false,
    'Gatsby' : false,
    'Lee' : false,
  });
  const [createdAt, setCreatedAt] = useState("");

  // fakeData 가져오기
  // const [letters, setLetters] = useState(fakeData);

  const [letters, setLetters] = useState([]);
  useEffect(()=>{
    const lettersData = require("../database/fakeData.json");
    setLetters(lettersData);
  },[])

  const nowTime = moment().format('YYYY-MM-DD HH:mm:ss');
  console.log(nowTime);

  useEffect(()=> {
    // GET CURRNET DATE & TIME
    const now = moment();
    // FORMATTING
    const formattedTime = now.format('YY-MM-DD HH:mm:');
    setCreatedAt(formattedTime);
  },[])

  const userNameRef = useRef('');
  useEffect(()=> {
    userNameRef.current.focus();
  })


  return (
    <div>
      <GlobalStyle />
      <Header letters={letters} setLetters={setLetters} userNameRef={userNameRef}/>
      <Main>
        <ImgBtnBox>
          <PicturePaul src={picturePaul} alt="Paul picture"/>
          {/* <Image /> */}
          <Button setLetterShown={setLetterShown} letters={letters}/>
        </ImgBtnBox>
        <List letters={letters.filter((letter)=>{
          return letterShown[letter.wroteTo];  
        })}/>
      </Main>
      <Footer />
    </div>
  );
}

export default Home;

 

 

따라서 letter 를 눌렀을 때 상세페이지로 넘어가게 하려면 <List> 컴포넌트에서 useParams 와 Link 작업을 해줘야 한다.

 

List.jsx

  • Link, useParams 를 import 하기
  • letter 에 해당되는 태그 속성에 아래 코드 추가하기
to={`/letter-details/${letter.id}`

 

 

여기서 잠깐,

현재 Letter 로 컴포넌트화가 되어 styled-components로 꾸며져있는 태그를 Link 로 바꾸면 꾸미기 적용이 당연히 안된다.

이럴 땐, styled-components 를 꾸며주는 선언부에서 styled.div``; 에서 styled(Link)``; 로 바꿔주면 된다.

 

React Router Link 태그에 styled-components 적용하기

styled. 이 아닌, styled()를 사용하여,styled(Link) 이렇게 스타일 적용.

velog.io

//BEFORE
const Letter = styled.div`
  display: flex;
	....
  }
`;
//AFTER
const Letter = styled(Link)`
  display: flex;
	....
  }
`;

 

 

전체코드

더보기

 

import React from 'react'
import {styled} from "styled-components";
import uuid from 'react-uuid';
import userIcon from '../assets/user-icon.png';
import { Link, useParams } from 'react-router-dom';


const ListArea = styled.div`
  border: 1px solid black;
  width: 450px;
  height: 400px;
  margin: 50px 25px 50px 25px;
  overflow-y: scroll;
`;

const Letter = styled(Link)`
  display: flex;
  flex-direction: row;
  justify-content: space-between;
  align-items: center;
  color: black;
  background-color: #e9e9e9;
  margin: 20px;
  padding: 10px;
  gap: 5px;
  height: 180px;
  cursor: pointer;
  text-decoration: none;
  transition: 0.3s ease;
  &:hover {
    transform: scale(1.02);
    background-color: #acacac;
  }
`;

const Message = styled.span`
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;  
`;

const UserIcon = styled.img`
  align-self: start;
  margin: 20px;
  width: 50px;
`;

function List({letters, setLetters}) {
  return (
    <ListArea>
      {letters.map((letter)=>{
        return(
          <Letter key={uuid()} to={`/letter-details/${letter.id}`}>
            <UserIcon src={userIcon} alt="User Icon"/>
            <div>
              <h3>{letter.userName}</h3>
              <p>{letter.createdAt}</p>
              <span>To...{letter.wroteTo},&nbsp;</span>
              <Message>{letter.message}</Message>
              <p>{uuid()}</p>
            </div>
          </Letter>
        );
      })}
    </ListArea>
  )
}

export default List
728x90
반응형