하루 하나씩 작성하는 TIL #27
mkdir 폴더명
cd 폴더명
git clone [GITHUB_URL] ./
git checkout -b ex1
yarn add react-router-dom
import "./App.css";
function App() {
/**
* TODO: 아래와 같은 구조로 컴포넌트를 만들고 Browser Router 설정하세요. UI는 신경쓰지 않습니다. 별도의 Router 컴포넌트 생성 여부는 자유입니다.
* Home 컴포넌트는 <Link> 컴포넌트를 사용해서 Detail 컴포넌트로 이동하도록 하세요.
* Detail 컴포넌트를 path parameter 로 id 를 받도록 하세요.
* Detail 컴포넌트는 path parameter 로 받은 id 를 콘솔로그로 찍으세요.
*
* src/
|-- pages/
| |-- Home.jsx
| |-- Detail.jsx
|-- App.jsx
*/
return <></>;
}
export default App;
src>pages>Home.jsx
import { Link } from 'react-router-dom';
const Home = () => {
return (
<div>
<h1>홈 페이지</h1>
<Link to="/detail/1">ID 1의 상세 페이지로 이동</Link>
</div>
);
};
export default Home;
src>pages>Detail.jsx
import { useParams } from 'react-router-dom';
const Detail = () => {
const { id } = useParams();
console.log(id); // 콘솔에 id를 출력합니다
return (
<div>
<h1>상세 페이지</h1>
<p>ID: {id}</p>
</div>
);
};
export default Detail;
scr>App.jsx
import { BrowserRouter as Router, Route, Routes } from 'react-router-dom';
import Home from './pages/Home';
import Detail from './pages/Detail';
function App() {
return (
<Router>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/detail/:id" element={<Detail />} />
</Routes>
</Router>
);
}
export default App;
App.jsx
import BoxContainer from "./components/BoxContainer";
function App() {
// Box 를 클릭하면 해당 Box만 파란색이 되도록 해야 합니다. components/ 안의 컴포넌트들안에서 TODO를 확인하세요.
// TODO: GlobalStyle 컴포넌트를 만들고 styled-reset 패키지로 스타일 초기화하고 App 컴포넌트에 적용해 보세요.
return (
<div>
<h1>Clickable Boxes</h1>
<BoxContainer />
</div>
);
}
export default App;
Box.jsx
import React from "react";
import styled from "styled-components";
// TODO: props로 받은 $active 에 따라 배경색이 blue 또는 gray가 되도록 해보세요.
const StyledBox = styled.div`
width: 100px;
height: 100px;
background-color: "gray";
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
color: white;
font-size: 20px;
`;
function Box({ active, onClick }) {
return <StyledBox $active={active} onClick={onClick} />;
}
export default Box;
BoxContainer.jsx
import React, { useState } from "react";
import styled from "styled-components";
import Box from "./Box";
const Container = styled.div`
display: flex;
gap: 10px;
`;
function BoxContainer() {
const [activeIndex, setActiveIndex] = useState(0);
const handleClick = (index) => {
setActiveIndex(index);
};
return (
<Container>
{/* TODO: active prop 을 어떻게 해야 클릭한 박스임을 알수있을 지 active prop에 할당할 값을 수정해보세요. */}
{[0, 1, 2, 3, 4].map((index) => (
<Box key={index} active={false} onClick={() => handleClick(index)} />
))}
</Container>
);
}
export default BoxContainer;
yarn add styled-reset
App.jsx
import BoxContainer from "./components/BoxContainer";
import GlobalStyle from "./components/GlobalStyle";
function App() {
return (
<div>
<GlobalStyle />
<h1>박스를 클릭해보세요</h1>
<BoxContainer />
</div>
);
}
export default App;
: 전역 스타일을 설정하는 GlobalStyle 컴포넌트를 렌더링 해준다. 리액트 애플리케이션 내의 모든 요소에 적용된다.
: BoxContainer 컴포넌트를 렌더링. 이 컴포넌트는 클릭 가능한 박스들을 표시하고, 해당 박스를 클릭할 때의 동작을 담당한다.
BoxContainer.jsx
import { useState } from "react";
import styled from "styled-components";
import Box from "./Box";
const Container = styled.div`
display: flex;
gap: 10px;
`;
function BoxContainer() {
const [activeIndex, setActiveIndex] = useState(0);
const handleClick = (index) => {
setActiveIndex(index);
};
return (
<Container>
{/* TODO: active prop 을 어떻게 해야 클릭한 박스임을 알수있을 지 active prop에 할당할 값을 수정해보세요. */}
{[0, 1, 2, 3, 4].map((index) => (
<Box key={index}
active={index === activeIndex}
onClick={() => handleClick(index)} />
))}
</Container>
);
}
export default BoxContainer;
배열의 map 함수를 사용하여 0부터 4까지의 숫자를 반복하며 Box 컴포넌트를 렌더링해준다.
각 박스는 key prop으로 고유한 키를 받고, active prop으로 현재 활성화된 박스인지 여부를 전달받는다.
또한 onClick prop으로 클릭 이벤트 핸들러를 받아 클릭할 때마다 해당 박스의 인덱스를 상태로 설정합니다.
이렇게 하면 BoxContainer 컴포넌트를 사용하여 클릭 가능한 박스들을 표시하고, 클릭한 박스를 활성화 상태로 변경할 수 있다.
Box.jsx
import PropTypes from "prop-types";
import styled from "styled-components";
const StyledBox = styled.div`
width: 100px;
height: 100px;
background-color: ${(props) => (props.$active ? "blue" : "gray")};
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
color: white;
font-size: 20px;
`;
function Box({ active, onClick }) {
return <StyledBox $active={active} onClick={onClick}>Box</StyledBox>;
}
Box.propTypes = {
active: PropTypes.bool.isRequired,
onClick: PropTypes.func.isRequired,
};
export default Box;
{(props) => (props.active ? "blue" : "gray")} 부분은 JavaScript의 삼항 연산자를 사용하여 props.$active가 참이면 "blue"를 반환하고, 그렇지 않으면 "gray"를 반환한다.
GloabalStyle.jsx
import { createGlobalStyle } from "styled-components";
import reset from "styled-reset";
const GlobalStyle = createGlobalStyle`
${reset}
body {
font-family: Arial, sans-serif;
}
`;
export default GlobalStyle;
App.jsx
import React, { useState, useEffect } from "react";
import TextInput from "./components/TextInput";
function App() {
// TODO: 로컬 스토리지에서 초기 상태로 사용할 값을 가져오세요. 새로고침 해도 기존 상태를 유지하는 것이 목적입니다.
// 로컬스토리지에 값이 없을 경우 빈배열[] 로 설정하세요.
const [texts, setTexts] = useState([]);
useEffect(() => {
// TODO: 상태가 변경될 때마다 로컬 스토리지에 저장. key 값은 texts 로 합시다.
}, [texts]);
const onAddText = (text) => {
setTexts((prevTexts) => [...prevTexts, text]);
};
return (
<div>
<h1>Text Input and Listing</h1>
<TextInput onAddText={onAddText} />
<ul>
{texts.map((text, index) => (
<li key={index}>{text}</li>
))}
</ul>
</div>
);
}
export default App;
import { useState, useEffect } from "react";
import TextInput from "./components/TextInput";
function App() {
// TODO: 로컬 스토리지에서 초기 상태로 사용할 값을 가져오세요. 새로고침 해도 기존 상태를 유지하는 것이 목적입니다.
// 로컬스토리지에 값이 없을 경우 빈배열[] 로 설정하세요.
const [texts, setTexts] = useState([]);
useEffect(() => {
// TODO: 상태가 변경될 때마다 로컬 스토리지에 저장. key 값은 texts 로 합시다.
localStorage.setItem('texts', JSON.stringify(texts));
}, [texts]);
const onAddText = (text) => {
setTexts((prevTexts) => [...prevTexts, text]);
};
return (
<div>
<h1>Text Input and Listing</h1>
<TextInput onAddText={onAddText} />
<ul>
{texts.map((text, index) => (
<li key={index}>{text}</li>
))}
</ul>
</div>
);
}
export default App;
ex3는 맞는지 확신이 없다
월요일 수업 때 피드백을 참고해야겠다.