내가 학생을 추가하면, 캘린더 화면에서도 해당 날짜에 학생을 볼 수 있어야 한다.
1. 유저가 정보를 입력한다.
2. 저장 버튼을 누른다.
3. 학생을 추가한다.
- 상위 컴포넌트로 전송한다.
4. 캘린더 화면(메인 화면)에는 학생 정보가 그려져있다.
궁금점
input값을 받고, state를 저장하는 함수를 하위 컴포넌트에다 써야하는건가? 하위컴포넌트에다 쓴다면, 해당 함수와 state모두 하위컴포넌트에 있겠지. 그다음에 상위 컴포넌트로 전송하는 걸꺼야.
그런데 이런 방법도 있다. 그냥 해당 함수랑 state모두 상위 컴포넌트에 만들어놓을 수 있다. 그런데 이런게 가능한가? 함수를 상위 컴포넌트에 만들어놓고, 하위 컴포넌트에서 쓸 수가 있는거야?? 정말로?
알아보자!
일단 하위 컴포넌트에서 올리는 건 Lifting State Up 으로 검색하면 된다.
우리가 알고 있듯이, 리액트의 모든 컴포넌트는 고유한 state를 가진다. 이거때문에, 가끔씩 데이터는 불필요하고, 일관적이지 않다. 그래서 state를 끌어올림으로써 우리는 부모 컴포넌트의 state를 유일한 진실의 근원으로 만들고, 부모의 데이터를 자식한테 보낼 수 있다.
Problem
A
/ \
B C
이렇게 부모컴포넌트 A와 자식 컴포넌트 B, C가 있다고 하자. 만약 B에만 어떤 데이터가 있는데, C가 그 데이터를 원한다면? C는 그 데이터에 접근할 수 없다. 컴포넌트는 자신의 부모컴포넌트나 자식컴포넌트에게만 얘기할 수 있기 때문이다.
이 문제를 해결하려면, 우리는 B와 C가 가진 state를 A로 끌어올려야 한다.
const [todos, setTodos] = React.useState(["item 1", "item 2", "item 3"]);
return (
<>
<TodoCount todos={todos}></TodoCount>
<TodoList todos={todos}></TodoList>
<AddTodo setTodos={setTodos}></AddTodo>
</>
);
(2) 렌더링하고싶은 부분에 {데이터}쓰기
function TodoCount({ todos }) {
return <div>Total Todos:{todos.length}</div>;
}
(3) state바꾸는 컴포넌트는 set어쩌구로
return(
...
<AddTodo setTodos={setTodos}></AddTodo>
...
function AddTodo({ setTodos }) {
function handleSubmit(event) {
event.preventDefault();
const todo = event.target.elements.todo.value;
setTodos((prevTodos) => [...prevTodos, todo]);
}
return (
<form onSubmit={handleSubmit}>
<input type="text" id="todo"></input>
<button type="submit">Add Todo</button>
</form>
);
}
근데 얘네는 왜 props.todo로 이렇게 안하는거야?
나는 컴포넌트이름(props) 이렇게 쓰는 걸로 아는데..
-> props라는 파라미터엔 전송한 모든 props 데이터가 들어있다. 그런데 이 예시에선 단순한 배열이므로 그냥 {데이터} 이런식으로 쓴 것이다. 만약 props중에서 골라서 쓰고 싶다면 {props.원하는거}이렇게 쓰면 되겠다.
오류
App.js
import React, { useState } from "react";
import "./App.scss";
// import dayjs from "dayjs";
import { BrowserRouter, Route, Routes } from "react-router-dom";
import Calendar from "./Components/Calendar.js";
import Homework from "./Components/Homework";
import HomeworkView from "./Components/HomeworkView";
import BuildProfile from "./Components/BuildProfile";
import Profiles from "./Components/Profiles";
function App() {
const [student, setStudent] = useState([
{
id: "",
name: "",
school: "학교이름",
age: "",
hourlyTuition: "",
onWeek: "",
hoursAWeek: "",
totalNum: "",
totalTuition: "",
firstDate: "",
days: "",
memo: "",
},
]);
console.log(student);
return (
<div className="App">
<BrowserRouter>
<header>
<nav></nav>
</header>
<main>
{student[0].school}
<Routes>
<Route path="/" element={<Calendar />}></Route>
</Routes>
</main>
<footer></footer>
{student[0].studentname}
<Routes>
<Route exact path="/homework" element={<Homework></Homework>}></Route>
<Route
exact
path="/homeworkview"
element={<HomeworkView></HomeworkView>}
></Route>
<Route
path="/buildprofile"
element={
<BuildProfile
student={student}
setStudent={setStudent}
></BuildProfile>
}
></Route>
<Route
path="/profiles"
element={<Profiles student={student}></Profiles>}
></Route>
</Routes>
</BrowserRouter>
</div>
);
}
export default App;
BuildProfile.js
import React from "react";
import { useState } from "react";
import "../Styles/student.scss";
const BuildProfile = (props) => {
const [schoolInput, setSchoolInput] = useState("");
function schoolChg(e) {
setSchoolInput(e.target.value);
props.setStudent[0].school("바꼈음");
console.log(props.student[0].school);
}
return (
<div>
<div>학생 프로필 작성</div>
<form>
<div className="studentInfo">
<div className="studentInfo--img">
<p>사진</p>
<input type="file" accept="image/*"></input>
</div>
<div className="studentInfo--right">
<div className="studentInfo__color">
<p>색상</p>
<div className="colors">
<div className="color"></div>
</div>
</div>
<div className="studentInfo__name">
<p>이름</p>
<input type="text"></input>
</div>
<div className="studentInfo__school">
<p>학교</p>
<input type="text" onChange={schoolChg}></input>
</div>
<div>{schoolInput}</div>
<div className="studentInfo__age">
<p>나이</p>
<input type="number"></input>
</div>
<div className="studentInfo__tuition">
<p>수업료</p>
<div className="studentInfo__tuition--inputs">
<div className="studentInfo__tuition__args">
<p className="studentInfo__tuition__p">
시간당 <input type="number"></input>만원
</p>
<p className="studentInfo__tuition__p">
주<input type="number"></input>회
</p>
<p className="studentInfo__tuition__p">
<input type="number"></input>시간
</p>
</div>
<div className="studentInfo__tuition__result">
<p className="studentInfo__tuition__p">
총 <input type="number"></input>회
</p>
<p className="studentInfo__tuition__p">
<input type="number"></input>
만원
</p>
</div>
</div>
</div>
<div className="studentInfo__first-date">
<p>수업 시작일</p>
<input type="date"></input>
</div>
<div className="studentInfo__days">
<p>요일</p>
<div className="studentInfo__days__collection">
<div className="studentInfo__days__day">월</div>
<div className="studentInfo__days__day">화</div>
<div className="studentInfo__days__day">수</div>
<div className="studentInfo__days__day">목</div>
<div className="studentInfo__days__day">금</div>
<div className="studentInfo__days__day">토</div>
<div className="studentInfo__days__day">일</div>
</div>
</div>
<div className="studentInfo__memo">
<p>메모</p>
<input type="text"></input>
</div>
</div>
</div>
<button>저장</button>
</form>
</div>
);
};
export default BuildProfile;
12월 26일 18:13
const BuildProfile = ({ student, setStudent }) => {
const [schoolInput, setSchoolInput] = useState("");
function schoolChg(e) {
setStudent({ ...student, school: e.target.value });
console.log({ student });
}
return (
...
)
import React, { useState } from "react";
import "./App.scss";
// import dayjs from "dayjs";
import { BrowserRouter, Route, Routes } from "react-router-dom";
import Calendar from "./Components/Calendar.js";
import Homework from "./Components/Homework";
import HomeworkView from "./Components/HomeworkView";
import BuildProfile from "./Components/BuildProfile";
import Profiles from "./Components/Profiles";
function App() {
const [student, setStudent] = useState({
id: "",
name: "",
school: "학교이름",
age: "",
hourlyTuition: "",
onWeek: "",
hoursAWeek: "",
totalNum: "",
totalTuition: "",
firstDate: "",
days: "",
memo: "",
});
console.log(student);
return (
<div className="App">
<BrowserRouter>
<main>
school: {student.school}
<Routes>
<Route path="/" element={<Calendar />}></Route>
</Routes>
</main>
<BuildProfile student={student} setStudent={setStudent}></BuildProfile>
<Profiles student={student}></Profiles>
<Routes>
<Route exact path="/homework" element={<Homework></Homework>}></Route>
<Route
exact
path="/homeworkview"
element={<HomeworkView></HomeworkView>}
></Route>
<Route
path="/buildprofile"
element={
<BuildProfile
student={student}
setStudent={setStudent}
></BuildProfile>
}
></Route>
<Route
path="/profiles"
element={<Profiles student={student}></Profiles>}
></Route>
</Routes>
</BrowserRouter>
</div>
);
}
export default App;