Frontend ๐Ÿ“š/React

[React]GitHub Pages + React๋กœ ๋‚˜๋งŒ์˜ ํฌํŠธํด๋ฆฌ์˜ค ๋งŒ๋“ค๊ธฐ - 5. ํ”„๋กœ์ ํŠธ ์Šฌ๋ผ์ด๋” + ํ”„๋กœ์ ํŠธ ๋‚ด ์ด๋ฏธ์ง€ ์Šฌ๋ผ์ด๋”

leejaejae 2024. 9. 20. 19:19

1. ํ”„๋กœ์ ํŠธ ์Šฌ๋ผ์ด๋”

- ๋‚ด๊ฐ€ ์ฐธ์—ฌํ–ˆ๋˜ ํ”„๋กœ์ ํŠธ๋“ค์„ ์›๋ž˜๋Š” aํƒœ๊ทธ๋งŒ ๋‹ฌ์•„์„œ ํ•ด๋‹น ํŽ˜์ด์ง€๋กœ ๋„˜๊ธฐ๋ ค๊ณ  ํ–ˆ๋Š”๋ฐ, ๊ฐ„๋žตํ•œ ์†Œ๊ฐœ๊ฐ€ ์žˆ์œผ๋ฉด ์ข‹์„ ๊ฒƒ ๊ฐ™์•„์„œ ํ”„๋กœ์ ํŠธ ์Šฌ๋ผ์ด๋”๋ฅผ ๋งŒ๋“ค๊ธฐ๋กœ ๊ฒฐ์ •!

1) ํ”„๋กœ์ ํŠธ ๋‚ด์šฉ ํŒŒ์ผ ์ƒ์„ฑ

- ์šฐ์„ , ํ”„๋กœ์ ํŠธ ๋‚ด์šฉ๋“ค์„ ๊ฐ์ฒด ๋ฐฐ์—ด ํ˜•ํƒœ๋กœ ์ •๋ฆฌํ•ด์„œ projectItems๋ผ๋Š” ์ด๋ฆ„์œผ๋กœ ์ €์žฅํ•จ.

projectItems.js

export const projectItems = [
  {
    title: "๐Ÿ›’๋ฌผํ’ˆ๋Œ€์—ฌ์„œ๋น„์Šค",
    category: "๊ฐœ์ธ ํ”„๋กœ์ ํŠธ",
    imageUrl: ``,
    githubLink: "",
    description:
      "",
    features:
      "",
    techStack: "",
  },
  {
    title: "๐Ÿ’‍โ™€๏ธ๋‚˜๋งŒ์˜ ํฌํŠธํด๋ฆฌ์˜ค",
    category: "๊ฐœ์ธ ํ”„๋กœ์ ํŠธ",
    imageUrl: ``,
    githubLink: "",
    description:
      "",
    features:
      "",
    techStack: "",
  },
];

- ์ดํ›„ projectDetail์—์„œ importํ•ด ์‚ฌ์šฉ.

2) ํ”„๋กœ์ ํŠธ ๋‚ด์šฉ ๋ฟŒ๋ฆฌ๊ธฐ

ProjectDetail.js

import { projectItems } from "./ProjectItems";
 
...
 
const [currentProjectIndex, setCurrentProjectIndex] = useState(0);
 
  const handlePrevProject = () => {
    setCurrentProjectIndex((prevIndex) =>
      prevIndex === 0 ? projectItems.length - 1 : prevIndex - 1
    );
  };
 
  const handleNextProject = () => {
    setCurrentProjectIndex((prevIndex) =>
      prevIndex === projectItems.length - 1 ? 0 : prevIndex + 1
    );
  };

- ํ”„๋กœ์ ํŠธ๋ฅผ ๊ธฐ์ค€์œผ๋กœ ์–‘์˜† <, > ๋ฒ„ํŠผ์„ ๋ˆ„๋ฅด๋ฉด ํ”„๋กœ์ ํŠธ๊ฐ€ ๋ณ€๊ฒฝ๋˜๋Š” ์Šฌ๋ผ์ด๋“œ๋กœ ๊ตฌํ˜„ ์˜ˆ์ •์ด๋ผ, ํ˜„์žฌ ํ™”๋ฉด์— ๋ณด์—ฌ์ค„ ํ”„๋กœ์ ํŠธ ์ธ๋ฑ์Šค๋ฅผ ์ €์žฅํ•  ๊ฐ์ฒด currentProjectIndex ์ƒ์„ฑ.

- handlePrevProject() ํ•จ์ˆ˜์™€ handleNextProjext() ํ•จ์ˆ˜๋Š” ๋ฒ„ํŠผ์„ ๋ˆ„๋ฅด๋ฉด ํ™”๋ฉด์— ๋ณด์—ฌ์ค„ ํ”„๋กœ์ ํŠธ์˜ ์ธ๋ฑ์Šค๋ฅผ ๋ฐ”๊ฟ”์ฃผ๋Š” ํ•จ์ˆ˜์ž„.
- ๋‘ ํ•จ์ˆ˜ ๋ชจ๋‘ setCurrentProjectIndex์˜ ์ธ์ž๋กœ, ์ƒˆ๋กœ์šด ์ƒํƒœ๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” ์ฝœ๋ฐฑ ํ•จ์ˆ˜๋ฅผ ์ „๋‹ฌํ•จ(์ด๋•Œ prevIndex๋Š” ํ˜„์žฌ์˜ ํ”„๋กœ์ ํŠธ ์ธ๋ฑ์Šค๋ฅผ ๋‚˜ํƒ€๋ƒ„).
- handlePrevProject() ํ•จ์ˆ˜์˜ ๊ฒฝ์šฐ ์ด ๊ฐ’์ด 0์ด๋ฉด ๋งˆ์ง€๋ง‰ ํ”„๋กœ์ ํŠธ๋กœ ์ด๋™ํ•˜๊ณ , ๊ทธ๋ ‡์ง€ ์•Š์œผ๋ฉด ์ด์ „ ํ”„๋กœ์ ํŠธ๋กœ ์ด๋™.
- handleNextProjext() ํ•จ์ˆ˜์˜ ๊ฒฝ์šฐ prevIndex ๊ฐ’์ด ๋งˆ์ง€๋ง‰ ํ”„๋กœ์ ํŠธ์˜ ์ธ๋ฑ์Šค๋ฅผ ๊ฐ€๋ฆฌํ‚ค๊ณ  ์žˆ๋‹ค๋ฉด 0๋ฒˆ์งธ ํ”„๋กœ์ ํŠธ๋กœ ์ด๋™ํ•˜๊ณ , ๊ทธ๋ ‡์ง€ ์•Š๋‹ค๋ฉด ๋‹ค์Œ ํ”„๋กœ์ ํŠธ๋กœ ์ด๋™.

return (
    <div className="container project" ref={ref}>
      <h1 className="project-title">
        <a name="Project">Projects</a>
      </h1>
      <div className="project-card-wrapper">
        <div className="slide">
          <img
            src={process.env.PUBLIC_URL + "/projectImgs/left.png"}
            onClick={handlePrevProject}
          />
        </div>
        <Card className="project-card">
          <div className="project-order">
            {currentProjectIndex + 1} / {projectItems.length}
          </div>
          <h2 className="project-title">
            {projectItems[currentProjectIndex].title}
          </h2>
          <h4 style={{ textAlign: "center", width: "100%" }}>
            {projectItems[currentProjectIndex].category}
          </h4>
          <section>
            <div className="project-img"></div>
          </section>
          <section>
            <article className="info-article">
              <p className="link-wrapper">
                Github
                <br />
              </p>
              <a href={projectItems[currentProjectIndex].githubLink}>
                {projectItems[currentProjectIndex].title}
              </a>
            </article>
            <article>
              <h3>ํ”„๋กœ์ ํŠธ ์†Œ๊ฐœ</h3>
              <p
                dangerouslySetInnerHTML={{
                  __html: projectItems[currentProjectIndex].description,
                }}
              ></p>
              <h3>์ฃผ์š” ๊ธฐ๋Šฅ</h3>
              <p
                dangerouslySetInnerHTML={{
                  __html: projectItems[currentProjectIndex].features,
                }}
              ></p>
              <h3>๊ธฐ์ˆ ์Šคํƒ</h3>
              <p>{projectItems[currentProjectIndex].techStack}</p>
            </article>
          </section>
        </Card>
        <div className="slide">
          <img
            src={process.env.PUBLIC_URL + "/projectImgs/right.png"}
            onClick={handleNextProject}
          />
        </div>
      </div>
    </div>
  );
});

- projectItems ๋ฐ์ดํ„ฐ๋ฅผ ์ด์šฉํ•ด ๋™์ ์œผ๋กœ ๋ฐ์ดํ„ฐ ํ™”๋ฉด์— ๋ฟŒ๋ ค์ฃผ๊ธฐ.
- <Card className="project-card"></Card> ์–‘ ์˜†์— <div className="slide"></div> ๋‚ด๋ถ€ ํ™”์‚ดํ‘œ ์ด๋ฏธ์ง€์— ๊ฐ๊ฐ ๋‹ฌ์•„์คŒ.

3) ์ด๋ฏธ์ง€ ์Šฌ๋ผ์ด๋“œ

- ์›๋ž˜๋Š” ํ”„๋กœ์ ํŠธ ๋‚ด์˜ ์ด๋ฏธ์ง€๋„ ์›๋ž˜๋Š” ๋Œ€ํ‘œ ์ด๋ฏธ์ง€ ํ•œ ์žฅ๋งŒ ๋ณด์—ฌ์ฃผ๋ ค๊ณ  ํ–ˆ๋Š”๋ฐ ์ด๋ฏธ์ง€๋กœ ์Šฌ๋ผ์ด๋”๋กœ ๋ณด์—ฌ์ฃผ๊ธฐ๋กœ ๊ฒฐ์ •ํ•จ.

projectItems.js

export const projectItems = [
  {
    title: "๐Ÿ›’๋ฌผํ’ˆ๋Œ€์—ฌ์„œ๋น„์Šค",
    category: "๊ฐœ์ธ ํ”„๋กœ์ ํŠธ",
    imageUrls: [
	  ...
    ],
  },
  ...
]

- ๋จผ์ € imageUrl์„ ๋ฐฐ์—ด๋กœ ์„ ์–ธ.

ProjectDetail.js

import { projectItems } from "./ProjectItems";
 
...
 
  const [currentProjectIndex, setCurrentProjectIndex] = useState(0);
  const [currentImageIndex, setCurrentImageIndex] = useState(0);
  
  const imageUrls = projectItems[currentProjectIndex].imageUrls;
  const hasMultipleImages = imageUrls.length > 1;

  const handlePrevProject = () => {
    setCurrentProjectIndex((prevIndex) =>
      prevIndex === 0 ? projectItems.length - 1 : prevIndex - 1
    );
    setCurrentImageIndex(0); // ํ”„๋กœ์ ํŠธ ๋ณ€๊ฒฝ ์‹œ ์ด๋ฏธ์ง€ ์Šฌ๋ผ์ด๋” ์ดˆ๊ธฐํ™”
  };

  const handleNextProject = () => {
    setCurrentProjectIndex((prevIndex) =>
      prevIndex === projectItems.length - 1 ? 0 : prevIndex + 1
    );
    setCurrentImageIndex(0);
  };

  const handlePrevImage = () => {
    setCurrentImageIndex((prevIndex) =>
      prevIndex === 0
        ? projectItems[currentProjectIndex].imageUrls.length - 1
        : prevIndex - 1
    );
  };

  const handleNextImage = () => {
    setCurrentImageIndex((prevIndex) =>
      prevIndex === projectItems[currentProjectIndex].imageUrls.length - 1
        ? 0
        : prevIndex + 1
    );
  };
  
  ...

- currentImageIndex ์ƒํƒœ ๋ณ€์ˆ˜ ์ƒ์„ฑํ•ด์„œ ํ˜„์žฌ ์„ ํƒ๋œ ํ”„๋กœ์ ํŠธ ๋‚ด์—์„œ์˜ ์ด๋ฏธ์ง€ ์ธ๋ฑ์Šค๋ฅผ ๊ด€๋ฆฌ(์ดˆ๊ธฐ๊ฐ’ 0).
-  imageUrls ๋ฐฐ์—ด ๋ณ€์ˆ˜ ์„ ์–ธํ•ด ํ˜„์žฌ ํ”„๋กœ์ ํŠธ์˜ ์ด๋ฏธ์ง€๋ฅผ ๋‹ค๋ฃฐ ์ˆ˜ ์žˆ๊ฒŒ ํ•จ.

- ์ด๋ฏธ์ง€๊ฐ€ ํ•œ์žฅ ๋ฟ์ธ ํ”„๋กœ์ ํŠธ๋ฅผ ๊ณ ๋ คํ•ด, ์ด๋ฏธ์ง€๊ฐ€ ์—ฌ๋Ÿฌ ์žฅ์ธ ํ”„๋กœ์ ํŠธ๋งŒ ์ด๋ฏธ์ง€ ์œ„์— ์˜†์œผ๋กœ ๊ฐ€๊ธฐ ๋ฒ„ํŠผ์ด ๋ณด์ด๋„๋ก ์„ค์ •ํ•˜๊ณ  ์‹ถ์—ˆ์Œ.
- hasMultipleImages ๋ถˆ๋ฆฌ์–ธ ๋ณ€์ˆ˜๋ฅผ ์„ ์–ธํ•ด ํ˜„์žฌ ํ”„๋กœ์ ํŠธ์˜ ์ด๋ฏธ์ง€๊ฐ€ ๋‘ ์žฅ ์ด์ƒ์ธ์ง€ ์—ฌ๋ถ€๋ฅผ ํ™•์ธํ•จ.
- ๊ทธ๋ž˜์„œ ์ด๋ฏธ์ง€๊ฐ€ ์—ฌ๋Ÿฌ ์žฅ์ผ ๊ฒฝ์šฐ์—๋งŒ ์Šฌ๋ผ์ด๋”๊ฐ€ ์ž‘๋™ํ•˜๊ฒŒ๋” ์‚ฌ์šฉ.

return (
    <div className="container project" ref={ref}>
      <h1 className="project-title">
        <a name="Project">Projects</a>
      </h1>
      
      ...
      
          <section>
            <div className="project-img">
              <div className="slider">
                <img
                  src={
                    projectItems[currentProjectIndex].imageUrls[
                      currentImageIndex
                    ]
                  }
                  alt={projectItems[currentProjectIndex].title}
                />
                {hasMultipleImages && (
                  <div className="slider-controls">
                    <button onClick={handlePrevImage}>{"<"}</button>
                    <button onClick={handleNextImage}>{">"}</button>
                  </div>
                )}
              </div>
            </div>
          </section>
          <section>
            <article className="info-article">
             ...
            </article>
          </section>
        </Card>
        
        ...
        
    </div>
  );
});

- {hasMultipleImages && (...)} ์˜ ๊ฒฝ์šฐ, ์กฐ๊ฑด๋ถ€ ๋ Œ๋”๋ง์„ ํ†ตํ•ด, ํ˜„์žฌ ํ”„๋กœ์ ํŠธ์— ์ด๋ฏธ์ง€๊ฐ€ ์—ฌ๋Ÿฌ ์žฅ(hasMultipleImages) ์žˆ๋Š” ๊ฒฝ์šฐ์—๋งŒ ์Šฌ๋ผ์ด๋” ์ปจํŠธ๋กค์„ ๋ Œ๋”๋งํ•จ.
- hasMultipleImages๊ฐ€ true์ผ ๋•Œ, ์Šฌ๋ผ์ด๋” ์ปจํŠธ๋กค(์ด๋ฏธ์ง€ ์ „ํ™˜ ๋ฒ„ํŠผ)์ด ํ™”๋ฉด์— ๋‚˜ํƒ€๋‚จ.

 

2. ๊ฒฐ๊ณผ ๐ŸŽ‰