TIL #27 | React 프로젝트 진행

kibi·2023년 11월 16일
1

TIL (Today I Learned)

목록 보기
26/83

css 말줄임 사용하기

const StContent = styled.li`
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  max-width: 550px;
  height: 20px;
`;

클릭시 나타나는 카드 구현하기

먼저 기본값이 false인 state를 만든다.

  const [modalOpen, setModalOpen] = useState(false);

원하는 요소 선택시 state를 true로 만들어 주는 이벤트 핸들링을 구성한다.

        <InputBox onClick={handleModal}>
          아티스트를 위한 팬레터를 작성해주세요!
        </InputBox>
  const handleModal = () => {
    setModalOpen(true);
  };

조건부 렌더링을 통해 modalOpen이 true이면 LetterForm을, false이면 InputBox를 보여주도록 한다.

      {modalOpen ? (
        <LetterForm
          handleNickname={handleNickname}
          handleContent={handleContent}
          handleMember={handleMember}
          handleSubmit={handleSubmit}
          nickname={nickname}
          content={content}
          setModalOpen={setModalOpen}
        />
      ) : (
        <InputBox onClick={handleModal}>
          아티스트를 위한 팬레터를 작성해주세요!
        </InputBox>
      )}

창을 다시 닫기 위해서 LetterForm 안의 버튼에 닫기 이벤트 핸들링을 구성해준다.

    <StButton onClick={closeModal}>닫기</StButton>
  const closeModal = () => {
    setModalOpen(false);
  };

디폴트 레이아웃을 적용하지 않는 페이지로 이동

원래는 디폴트 레이아웃을 구성한 후 children으로 넣어주는 방법을 사용했었다.

function Layout({ children }) {
  return (
    <div>
      <StHeader>
        <img
          src={img}
          alt="title-logo"
          style={{ width: "30%", minWidth: "400px" }}
        />
      </StHeader>
      <StNav>
        <StNavLink to="/">Home</StNavLink>
        <StNavLink to="/letter">To.aespa</StNavLink>
      </StNav>
           <StLayout>{children}</StLayout>
      <StFooter>© EB Corp.</StFooter>
    </div>
  );
}

라우터에서도 <Layout>으로 <Routes>를 묶어주는 형식으로 사용해서
children값으로 라우트 컴포넌트가 들어오도록 구성했다.

  return (
    <BrowserRouter>
      <Layout />
      <Routes>
          <Route index path="/" element={<Home />} />
          <Route path="/letter" element={<Letter />} />
        <Route path="/letter/:id" element={<DetailLetter />} />
      </Routes>
      </Layout>
    </BrowserRouter>
  );
};

여기서 문제가 발생했다.
디폴트 레이아웃에 영향받지 않는 <DetailLetter> 페이지로 이동하기 위해 아래와 같이 사용해봤지만 적용되지 않거나 Routes 아래에 Layout을 사용할 수 없다는 에러가 발생했다.

       <Routes>
		<Layout />
          <Route index path="/" element={<Home />} />
          <Route path="/letter" element={<Letter />} />
          </Layout>
        <Route path="/letter/:id" element={<DetailLetter />} />
	   </Routes>

어떻게 이 문제를 해결할지 열심히 찾아보다가 해결방안이 보였다.
Layout과 Oulet을 사용하는 방법이다.


Layout과 Oulet을 이용한 라우터 구현

기존에는 children으로 값을 받아주는 방법을 사용했다.
이 방법에선 설정한 Layout으로 children을 감싸줬던 것처럼 Outlet을 import해서 <Outlet>을 감싸주면 된다.

import { Link, Outlet } from "react-router-dom";

      <StLayout>
        <Outlet />
      </StLayout>

그러면 아래와 같이 <Layout /> 을 Route의 element로 가져올 수 있기 때문에 Layout을 Routes 아래에 사용할 수 없다는 에러가 발생하지 않는다.
또한 Layout으로 감싸준 요소만 Outlet으로 받아지기 때문에 감싸주지 않은 요소는 디폴트 레이아웃의 영향을 받지 않게 된다.

<Routes>
      {/* Layout을 element만 이용해서 넣기 */}
      <Route element={<Layout />}>
        <Route path='/' element={<Home />} />
        <Route path='/about' element={<About />} />
        <Route path='/profiles/:username' element={<Profile />} />
      </Route>
      </Routes>

Link를 통해 값 보내고 가져오는 방법

Link를 통해 페이지를 이동할 경우 state={{ data: data}} 와 같은 형식으로 현재 내부에 있는 값을 보내줄 수 있다.

<Link to={`/letter/${id}`} key={id} state={{ data: item }}>

값을 받아올 때는 useLocation()을 사용한다.

  const location = useLocation();
  const data = location.state.data;

useParams는 파라미터 값을 가져올 수 있다.
즉, /:id와 같이 설정했을 때의 id 값을 받아올 수 있다.


로컬 경로에서 Json 파일 가져와 사용하기

json 파일을 로컬 경로에 가져온다.

require을 사용해서 json 데이터를 가져와 사용한다.

const jsonData = require("../letterData.json");

styled components 활용 방법


styled components에서 Link 컴포넌트 스타일링 하는 방법

  • styled(Link) 와 같이 Link를 괄호로 감싸주면 사용 가능하다.
const StNavLink = styled(Link)`
  color: var(--mainWhite);
  font-weight: 700;
  font-size: 1.5rem;
  transition: 0.3s;
  &:hover {
    color: var(--aespa4);
  }
`;

hover, focus 설정하는 방법

  • $:hover, $:focus를 사용하여 중괄호 안에 hover 또는 focus 발생 시 바뀔 스타일을 지정해준다.
cosnt StBox = styled.div`
	display: flex;
	&:hover {
		background-color: #fff
	}
`

태그 속성을 styled로 지정하는 방법

  • attributes를 사용하기 위해 .attrs({})를 사용한다.
const StInput = styled.input.attrs({
  required: true,
  maxLength: 20,
  placeholder: "20자 이내로 작성해주세요",
})`
  width: 25rem;
  font-size: small;
  padding: 0.25rem;
`;
  • passing props
const UseAttrsButton = styled(PassingPropsButton).attrs((props) => ({
  bg: "red",
  color: "blue",
}))`
  background-color: ${({ bg }) => bg};
  color: ${({ color }) => color};
`;

styled components를 단순한 방식으로만 사용했는데 사용법을 찾아보니 여러가지로 유용하게 쓸 수 있을 것 같아서 앞으로는 적극 활용해보려고 한다.
https://styled-components.com/docs styled components의 공식 페이지를 참고해서 공부해봐야겠다.


git branch 로컬 및 원격 브랜치 삭제 방법

로컬 브랜치 삭제
git branch -d <로컬 브랜치 이름>

원격 브랜치 삭제
git push <원격 저장소 이름> -d <원격 브랜치 이름>


문제 상황 해결

  • 구현하려는 것
    메인페이지에서 상세페이지로 이동 -> 수정 및 삭제 버튼 클릭 -> 메인페이지로 돌아와서 반영

보통 하위 컴포넌트로 값을 보낼 때는 props로 보내면 된다.
페이지를 이동하기 위해선 <Link> 컴포넌트를 사용해야 하는데 값을 보내줄 떄의 방법이 약간 다르다.
<Link>를 통해 값을 보내기 위해선 <Link to="경로" state={{ 변수명: 보낼값 }} /> 와 같이 구성하여 이동한 페이지에서 useLocation을 통해 state 값을 가져와 사용하면 된다.

하지만 여기서 setState와 같은 함수는 어떻게 보내줘야 하는지 의문이 생겼다.
보통 컴포넌트에서 props를 내려줄 때 setState={setState}와 같이 함수를 바로 내려줄 수 있었다. 그치만 아무리 찾아봐도 <Link> 를 통해 state가 아닌 함수를 내려주는 것은 어려워보였다. (물론 방법이 있겠지만)
이런 경우 대부분 useContext와 redux를 사용하라고 나와있었는데 useContext와 redux가 전역변수를 관리하는데 얼마나 유용하게 사용할 수 있는 방식인지 깨닫기도 했다.

그러다가 함수가 아닌 state만 내려서 반영하는 방법을 생각해냈다.

방법은 아래와 같다.

1) <Link to="경로" state={{ 변수명: 보낼값 }} /> 를 사용해 값을 보낸다.
2) 이동한 페이지에서 useLocation()을 사용하여 저장된 값을 가져와서 반영한다.

  const location = useLocation();
	
  const { id, nickname, avatar, member, createdAt, content } = location.state.data;

  const letterList = location.state.letterList;

3) 이동한 페이지에서 가져온 값을 변환하여 새로운 변수로 선언한다.

    const filteredList = letterList.filter((letter) => letter.id !== id);

4) 선언된 변수를 useNavigate()를 사용하여 state로 넘겨준다.

navigate("/letter", {
      state: [...filteredList],
    });

5) 메인 페이지로 돌아와서 useLocation()을 사용하여 저장된 값을 가져온다.

  const location = useLocation();
  const filteredLetters = location.state;

6) useEffect()를 사용해서 가져온 값이 존재하고 변경되었을 경우 상태를 변경해준다.

  useEffect(() => {
    if (filteredLetters) setLetterList(filteredLetters);
  }, [filteredLetters]);

이와 같이 해주면 상세페이지로 이동했던 값을 변경하여 다시 메인페이지로 변경값을 보내 반영해줄 수 있게 된다.

0개의 댓글