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을 사용하는 방법이다.
기존에는 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를 통해 페이지를 이동할 경우 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 파일을 로컬 경로에 가져온다.
require을 사용해서 json 데이터를 가져와 사용한다.
const jsonData = require("../letterData.json");
styled components에서 Link 컴포넌트 스타일링 하는 방법
const StNavLink = styled(Link)`
color: var(--mainWhite);
font-weight: 700;
font-size: 1.5rem;
transition: 0.3s;
&:hover {
color: var(--aespa4);
}
`;
hover, focus 설정하는 방법
cosnt StBox = styled.div`
display: flex;
&:hover {
background-color: #fff
}
`
태그 속성을 styled로 지정하는 방법
const StInput = styled.input.attrs({
required: true,
maxLength: 20,
placeholder: "20자 이내로 작성해주세요",
})`
width: 25rem;
font-size: small;
padding: 0.25rem;
`;
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 -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]);
이와 같이 해주면 상세페이지로 이동했던 값을 변경하여 다시 메인페이지로 변경값을 보내 반영해줄 수 있게 된다.