하루 하나씩 작성하는 TIL #30
src
ㄴ App.jsx
import { useState, useEffect } from "react";
import TextInput from "./components/TextInput";
import TextList from "./components/TextList";
function App() {
// TODO: texts 를 context api 로 리팩터링 하세요.
const [texts, setTexts] = useState(() =>
localStorage.getItem("texts")
? JSON.parse(localStorage.getItem("texts"))
: [],
);
useEffect(() => {
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} />
<TextList texts={texts} />
</div>
);
}
export default App;
src
ㄴcomponents
ㄴTextInput.jsx
import React, { useState } from "react";
function TextInput({ onAddText }) {
const [inputValue, setInputValue] = useState("");
const handleChange = (e) => {
setInputValue(e.target.value);
};
const handleSubmit = (e) => {
e.preventDefault();
if (inputValue.trim()) {
onAddText(inputValue);
setInputValue("");
}
};
return (
<form onSubmit={handleSubmit}>
<input
type="text"
value={inputValue}
onChange={handleChange}
placeholder="Enter text"
/>
<button type="submit">Add</button>
</form>
);
}
export default TextInput;
src
ㄴcomponents
ㄴTextList.jsx
import React, { useState } from "react";
function TextInput({ onAddText }) {
const [inputValue, setInputValue] = useState("");
const handleChange = (e) => {
setInputValue(e.target.value);
};
const handleSubmit = (e) => {
e.preventDefault();
if (inputValue.trim()) {
onAddText(inputValue);
setInputValue("");
}
};
return (
<form onSubmit={handleSubmit}>
<input
type="text"
value={inputValue}
onChange={handleChange}
placeholder="Enter text"
/>
<button type="submit">Add</button>
</form>
);
}
export default TextInput;
Context API를 통해 상태를 관리하기 위하여 Context파일을 생성해준다.
src
ㄴ TextContext.jsx
// src/TextContext.jsx
import React, { createContext, useState, useEffect } from "react"; // 필요한 React 훅과 createContext 함수를 import합니다.
import PropTypes from "prop-types"; // PropTypes를 import하여 prop 타입을 검사합니다.
// Context를 생성합니다.
const TextContext = createContext();
const TextProvider = ({ children }) => { // TextProvider 컴포넌트를 정의합니다. children prop을 받습니다.
// texts 상태를 초기화합니다. 로컬 스토리지에 저장된 값이 있으면 사용하고, 없으면 빈 배열을 사용합니다.
const [texts, setTexts] = useState(() =>
localStorage.getItem("texts")
? JSON.parse(localStorage.getItem("texts"))
: []
);
// texts 상태가 변경될 때마다 로컬 스토리지에 저장합니다.
useEffect(() => {
localStorage.setItem("texts", JSON.stringify(texts));
}, [texts]);
// 새로운 텍스트를 추가하는 함수를 정의합니다.
const addText = (text) => {
setTexts((prevTexts) => [...prevTexts, text]); // 이전 texts 배열에 새로운 텍스트를 추가합니다.
};
return (
<TextContext.Provider value={{ texts, addText }}> {/* TextContext.Provider를 사용해 texts와 addText 함수를 제공합니다. */}
{children} {/* Provider 내부의 children을 렌더링합니다. */}
</TextContext.Provider>
);
};
// children prop의 타입을 검사합니다.
TextProvider.propTypes = {
children: PropTypes.node.isRequired,
};
// TextContext와 TextProvider를 export합니다.
export { TextContext, TextProvider };
main.jsx파일에서 Textprovider를 사용하여 애플리케이션 감싸기
src
ㄴmain.jsx
// src/main.jsx
import React from "react"; // React를 import합니다.
import { createRoot } from "react-dom/client"; // createRoot를 import합니다.
import App from "./App.jsx"; // App 컴포넌트를 import합니다.
import { TextProvider } from "./TextContext.jsx"; // TextProvider를 import합니다.
const container = document.getElementById("root"); // root DOM 엘리먼트를 가져옵니다.
const root = createRoot(container); // createRoot를 사용해 root를 생성합니다.
root.render(
<TextProvider> {/* TextProvider로 App을 감쌉니다. */}
<App /> {/* App 컴포넌트를 렌더링합니다. */}
</TextProvider>
);
Context 사용하기 - TextInput.jsx와 TextList.jsx 컴포넌트에서 TextContext를 사용하여 상태에 접근하고 업데이트
src
ㄴcomponents
ㄴTextInpt.jsx
// src/components/TextInput.jsx
import React, { useState, useContext } from "react"; // React, useState, useContext를 import합니다.
import { TextContext } from "../TextContext.jsx"; // TextContext를 import합니다.
function TextInput() { // TextInput 컴포넌트를 정의합니다.
const [inputValue, setInputValue] = useState(""); // inputValue 상태를 초기화합니다.
const { addText } = useContext(TextContext); // TextContext에서 addText 함수를 가져옵니다.
const handleChange = (e) => { // 입력 값이 변경될 때 호출되는 함수입니다.
setInputValue(e.target.value); // inputValue 상태를 업데이트합니다.
};
const handleSubmit = (e) => { // 폼이 제출될 때 호출되는 함수입니다.
e.preventDefault(); // 폼의 기본 제출 동작을 막습니다.
if (inputValue.trim()) { // 입력 값이 비어 있지 않은 경우에만
addText(inputValue); // addText 함수를 호출하여 새로운 텍스트를 추가합니다.
setInputValue(""); // 입력 필드를 비웁니다.
}
};
return (
<form onSubmit={handleSubmit}> {/* 폼 제출 이벤트 핸들러를 설정합니다. */}
<input
type="text"
value={inputValue} {/* inputValue 상태를 input의 값으로 설정합니다. */}
onChange={handleChange} {/* 입력 값이 변경될 때 handleChange 함수를 호출합니다. */}
placeholder="Enter text" {/* 입력 필드에 플레이스홀더를 설정합니다. */}
/>
<button type="submit">Add</button> {/* 제출 버튼을 렌더링합니다. */}
</form>
);
}
export default TextInput; // TextInput 컴포넌트를 export합니다.
src
ㄴcomponents
ㄴTextList.jsx
// src/components/TextList.jsx
import React, { useContext } from "react"; // React와 useContext를 import합니다.
import { TextContext } from "../TextContext.jsx"; // TextContext를 import합니다.
function TextList() { // TextList 컴포넌트를 정의합니다.
const { texts } = useContext(TextContext); // TextContext에서 texts 배열을 가져옵니다.
return (
<ul>
{texts.map((text, index) => ( // texts 배열을 순회하며 각 텍스트를 li 요소로 렌더링합니다.
<li key={index}>{text}</li> // key로 인덱스를 사용하여 고유성을 보장합니다.
))}
</ul>
);
}
export default TextList; // TextList 컴포넌트를 export합니다.