๋๋ฏธ ๋ฐ์ดํฐ๋ก ๋ก๊ทธ์ธํ๊ธฐ
์ด๋ฒ์๋ ๋ก๊ทธ์ธ์ฆ, ๊ฐ์ง๋ก๊ทธ์ธ์ ๊ตฌํํด๋ณด๊ฒ ์ต๋๋ค.
๋จผ์ LoginForm์ submitํจ์๋ฅผ ๋ง๋ค์ด์ฃผ์ธ์
const onSubmitForm = useCallback(() => {
console.log(id, password);
setIsLoggedIn(true); //Props๋ก AppLayout์์ ๋ฐ์์ต๋๋ค.
}, [id, password]);
Ant-design์์๋ onSubmit ๋์ onFinish๋ฅผ ์ฌ์ฉํด
e.preventDefault ์ฆ ์๋ก๊ณ ์นจ์ ๋ง์์ค ์ ์์ต๋๋ค.
AppLayout.js๋ ๋ฐ๊ฟ์ค์ผ ๊ฒ ์ฃ ?
{isloggedIn ? <UserProfile /> : <LoginForm setIsLoggedIn={setIsLoggedIn}/>}
๋ง์ฝ ๋ก๊ทธ์ธ์ด true๋ฉด ํ๋กํ, false๋ฉด ๋ก๊ทธ์ธ์ฐฝ์ ๋์ฐ๋ ํ๋ฉด์
๋๋ค.
UserProfile.js ๋ง๋ค๊ธฐ
Ant-design์ Card๋ฅผ ์ด์ฉํด ์ ์ ํ๋กํ์ ๋ง๋ค์ด ๋ณด๊ฒ ์ต๋๋ค.
Card๋ ์ ๋ง ์ธ๋ชจ๊ฐ ๋ง์ผ๋ ํ๋ฒ ๊ตฌ๊ฒฝ๋ค๋
์ค์ธ์
์, ๊ทธ๋ผ ์ด์ UserProfile ์ปดํฌ๋ํธ๋ฅผ ์์ฑํด๋ณผ๊น์
UserProfile ์ปดํฌ๋ํธ ๋ง๋ค๊ธฐ
import React from "react";
import { Card, Avatar, Button } from "antd";
export default function UserProfile() {
return (
<Card
actions={[
//๋ฐฐ์ด์ด๊ธฐ๋๋ฌธ์ ํค๊ฐ์ ๋ฃ์ด์ค์ผ ํ๋ค.
<div key="twit">
์งน์งน
<br />0
</div>,
<div key="following">
ํ๋ก์
<br />0
</div>,
<div key="follower">
ํ๋ก์
<br />0
</div>,
]}
>
<Card.Meta avatar={<Avatar>CD</Avatar>} title="Conrad" />
<Button>๋ก๊ทธ์์</Button>
</Card>
);
}
Card์ ๊ดํ ์์ํ ๋ด์ฉ์ ๋ค๋ฃฐ๊ฒ์ด ๋ง์์ ์์ ๊ฐ๋ฐ์๋ฌธ์๋ฅผ ๋ณด๋ฉด ์ดํดํ ์ ์์ต๋๋ค.
์ด์ ํ์์ ๋ก๊ทธ์ธ ๋ฒํผ์ ๋๋ฅด๋ฉด?
์ด์ ๊ฐ์ง๋ก๊ทธ์์ ๊ธฐ๋ฅ๋ ๊ตฌํํด๋ณผ๊ฒ์
import React, { useCallback } from "react";
import { Card, Avatar, Button } from "antd";
export default function UserProfile({ setIsLoggedIn }) {
const onLogOut = useCallback(() => {
setIsLoggedIn(false);
}, []);
return (
<Card
actions={[
//๋ฐฐ์ด์ด๊ธฐ๋๋ฌธ์ ํค
<div key="twit">
์งน์งน
<br />0
</div>,
<div key="following">
ํ๋ก์
<br />0
</div>,
<div key="follower">
ํ๋ก์
<br />0
</div>,
]}
>
<Card.Meta avatar={<Avatar>CD</Avatar>} title="Conrad" />
<Button onClick={onLogOut}>๋ก๊ทธ์์</Button>
</Card>
);
}
๋ฌผ๋ก Applayout์์ Props๋ฅด ์ ๋ฌํด์ค์ผ ํ๋๊ฑธ ์์ผ๋ฉด ์๋ฉ๋๋ค.
์ด๋ฒ์๋ ํ๋กํ ํ์ด์ง๋ฅผ ๊ตฌ์ฑํด๋ณผ๊น์?
ํ๋กํ ํ์ด์ง๋ ๋ค์๊ณผ ๊ฐ์ด ๊ตฌ์ฑ๋์ด์์ต๋๋ค.
import React from "react";
import AppLayout from "../components/AppLayout";
import Head from "next/head";
import FollowList from "../components/FollowList";
import NicknameEditForm from "../components/NicknameEditForm";
export default function profile() {
//๊ฐ์ง ๋ฐ์ดํฐ
const followerList = [
{ nickname: "conrad" },
{ nickname: "Roo" },
{ nickname: "boo" },
];
const followingList = [
{ nickname: "conrad" },
{ nickname: "Roo" },
{ nickname: "boo" },
];
return (
<div>
<Head>
<title>ํ๋กํ | NodeBird</title>
</Head>
<AppLayout>
//๋๋ค์ ์์ ์ปดํฌ๋ํธ
<NicknameEditForm />
//๋ชฉ๋ก ์ปดํฌ๋ํธ 2๊ฐ
<FollowList header="ํ๋ก์ ๋ชฉ๋ก" data={followingList} />
<FollowList header="ํ๋ก์ ๋ชฉ๋ก" data={followerList} />
</AppLayout>
</div>
);
}
๋ค์์ ๊ฐ๋จํ NicknameEditForm.js๋ถํฐ ๋ง๋ค์ด๋ณผ๊น์?
import React, { useMemo } from "react";
import { Form, Input } from "antd";
function NicknameEditForm() {
const style = useMemo( //useMemo๋ฅผ ํตํ ๋ฆฌ๋๋๋ง ์ต์ ํ
() => ({
marginBottom: "28px",
border: "1px solid #d9d9d9",
padding: "30px",
}),
[]
);
return (
<Form style={style}>
<Input.Search addonBefore="๋๋ค์" enterButton="์์ " />
</Form>
);
}
export default NicknameEditForm;
๋ค์์ ๋ณต์กํ ์๋ ์๋ ๋ฆฌ์คํธ์
๋๋ค.
import React from "react";
import { List, Button, Card } from "antd";
import { StopOutlined } from "@ant-design/icons"; //์์ด์ฝ์ ์ฉ๋์ด ํฌ๊ธฐ ๋๋ฌธ์ ๋ฐ๋ก์๋ค.
export default function FollowList({ header, data }) {
return (
<List
style={{ marginBottom: 20 }}
//list์ด์ง๋ง grid๋ก
grid={{ gutter: 4, xs: 2, md: 3 }}
size="small"
header={<div>{header}</div>} //ํค๋
loadMore={ //๋๋ณด๊ธฐ ๋ฒํผ์ด ์๋ ์ปจํ
์ด๋
<div style={{ textAlign: "center", margin: "10px 0" }}>
<Button>๋ ๋ณด๊ธฐ</Button>
</div>
}
bordered
dataSource={data} //props๋ก ์ ๋ฌ๋ฐ์ ๋ฐ์ดํฐ
renderItem={(item) => ( //๋ฐ์ดํฐ์ ์์ดํ
๋ค์ ํตํด mapํจ์์ ๊ฐ์ ๊ฐ๋
<List.Item style={{ marginTop: 20 }}>
<Card actions={[<StopOutlined key="stop" />]}>
<Card.Meta description={item.nickname} />
</Card>
</List.Item>
)}
/>
);
}
๋ณด๋ฉด ๋ณต์กํด๋ณด์ผ์๋ ์์ง๋ง Ant-Design ๊ณต์๋ฌธ์์ ๋ค ๋์์๋ ๋ด์ฉ๋ค์
๋๋ค.
๋จธ๋ฆฌ์ ์ธ์ธํ์ ์์ด ๋ฌธ์ ๋ณด๋ฉด์ ์ฐ๊ณ ์ถ์ ๋ถ๋ถ๋ง ๊ฐ์ ธ๋ค๊ฐ ์ฐ๋ฉด ๋๋ ๊ฒ์ด์ฃ .
๊ฒฐ๊ณผ๋ฌผ์ ํ๋ฒ ๋ณผ๊น์?
๋ค์์๋ ์ปค์คํ
ํ
์ ์ด์ฉํ ํ์๊ฐ์
ํ์ด์ง๋ฅผ ๋ง๋ค์ด ๋ณด๊ฒ ์ต๋๋ค.
๋จผ์ ์ปดํฌ๋ํธ์
๋๋ค.
<AppLayout>
<Head>
<title>ํ์๊ฐ์
| NodeBird </title>
</Head>
<Form onFinish={onSubmit}>
<div>
<label htmlFor="user-id">์์ด๋</label>
<br />
<Input name="user-id" value={id} onChange={onChangeId} />
</div>
<div>
<label htmlFor="user-nickname">๋๋ค์</label>
<br />
<Input
name="user-nickname"
value={nickname}
onChange={onChangeNickname}
/>
</div>
<div>
<label htmlFor="user-password">๋น๋ฐ๋ฒํธ</label>
<br />
<Input
name="user-password"
type="password"
value={password}
onChange={onChangePassword}
/>
</div>
<div>
<label htmlFor="user-check">๋น๋ฐ๋ฒํธํ์ธ</label>
<br />
<Input
name="user-check"
type="password"
value={check}
onChange={onChangeCheck}
/>
</div>
{passwordError && (
<PasswordError>๋น๋ฐ๋ฒํธ๊ฐ ๋ง์ง ์์ต๋๋ค.</PasswordError>
)}
<Checkbox name="user-term" checked={term} onChange={onChangeTerm}>
๋์ํฉ๋๋ค.
</Checkbox>
{termError && <div style={{ color: "red" }}>์ฝ๊ด์ ๋์ํด์ฃผ์ธ์</div>}
<div style={{ marginTop: 10 }}>
<Button type="primary" htmlType="submit">
๊ฐ์
</Button>
</div>
</Form>
</AppLayout>
ant-design์ด๊ธฐ ๋๋ฌธ์ ์์ธํ ์ธ๊ธ์ ์ํ๊ฒ ์ต๋๋ค.
๋ค์์ผ๋ก๋ input์ ์ํ๊ฐ์ ๊ด๋ฆฌํด์ค๊ฑด๋ฐ์
input์ด ๋ง๊ธฐ ๋๋ฌธ์ useState๋ฅผ ์ฌ๋ฌ๋ฒ ์ฌ์ฉํด์ค์ผ ํ ๊ฒ ๊ฐ์ต๋๋ค.
const [id, setId] = useState("");
const [password, setPassword] = useState("");
ํ์ง๋ง ์ด๋ฐ์์ผ๋ก ๋ชจ๋ ์์ฑํ๋ ๊ฒ์ ๋นํจ์จ์ ์
๋๋ค.
ํด๊ฒฐ๋ฐฉ๋ฒ์ ๋๊ฐ์ง๊ฐ ์๋๋ฐ์
์ปค์คํ
ํ
์ ๋ง๋ค์ด ์ฌ์ฉํ๊ธฐ
useState์์ฒด๋ก ํด๊ฒฐํ๊ธฐ
์ปค์คํ
ํ
์ ๋จผ์ ๋ง๋ค์ด ๋ณผ๊น์?
import { useState, useCallback } from "react";
export default function useInput(initialValue = null) {
const [value, setValue] = useState(initialValue);
const handler = useCallback((e) => {
setValue(e.target.value);
}, []);
return [value, handler];
}
ํ
์์์ change๋๋ ๊ฐ๋ค์ ์ํ๋ก ๋ฐ๊ฟ์ค๋ค valuedhk ๋ฐ๊พธ๋ ํจ์๋ฅผ ๋ด๋ณด๋ด๋ ํ์์
๋๋ค.
๊ทธ๋ ๋ค๋ฉด ์ด๋ ๊ฒ ๊ตฌํํ ์ ์์ต๋๋ค.
const [id, onChangeId] = useInput("");
const [nickname, onChangeNickname] = useInput("");
const [password, onChangePassword] = useInput("");
๊ฐ๋จํด์ง์ฃ ?
๋ค์๋ฐฉ๋ฒ์ useState์ ๊ธฐ๋ณธ๊ฐ์ ๊ฐ์ฒด๋ก ๋ง๋๋ ๋ฐฉ๋ฒ์
๋๋ค.
const [inputs, setInputs] = useState({
id: '',
password: '',
nickname: ''
});
๊ทธ๋ค ๊ฐ์ ์ค์ ํ๋ ํจ์๋ฅผ ๊ตฌํํด๋ณด๋ฉด
const { id,password ,nickname } = inputs; // ๋น๊ตฌ์กฐํ ํ ๋น์ ํตํด ๊ฐ ์ถ์ถ
const onChange = (e) => {
const { value, name } = e.target; // ์ฐ์ e.target ์์ name ๊ณผ value ๋ฅผ ์ถ์ถ
setInputs({
...inputs, // ๊ธฐ์กด์ input ๊ฐ์ฒด๋ฅผ ๋ณต์ฌํ ๋ค
[name]: value // name ํค๋ฅผ ๊ฐ์ง ๊ฐ์ value ๋ก ์ค์
});
};
์ ๋๋ค ์ข์ ๋ฐฉ๋ฒ์ด๋ ํธํ ๋ฐฉ๋ฒ์ ์ฐ๋ฉด ๋ ๊ฒ ๊ฐ์ต๋๋ค.
์์ฑ๋ ์ ์ฒด ์ฝ๋๋ฅผ ๋ณด๊ฒ ์ต๋๋ค.
import React, { useCallback, useState } from "react";
import AppLayout from "../components/AppLayout";
import { Form, Input, Checkbox, Button } from "antd";
import Head from "next/head";
import styled from "styled-components";
import useInput from "../hooks/useInput";
const PasswordError = styled.div`
color: red;
`;
export default function signup() {
const [id, onChangeId] = useInput("");
const [nickname, onChangeNickname] = useInput("");
const [password, onChangePassword] = useInput("");
const [check, setCheck] = useState("");
const [passwordError, setPasswordError] = useState(false);
const [term, setTerm] = useState("");
const [termError, setTermError] = useState(false);
const onChangeCheck = (e) => {
setCheck(e.target.value);
setPasswordError(e.target.value !== password); //์ด๋ถ๋ถ์ด ๋ฌ๋ผ์ ๋ชปํ๋ค.
};
const onChangeTerm = useCallback((e) => {
setTerm(e.target.checked);
setTermError(false);
}, []);
//ํ๋ฒ๋ ์ฒดํฌ
const onSubmit = useCallback(() => {
if (password !== check) {
return setPasswordError(true);
}
if (!term) {
return setTermError(true);
}
console.log(id, nickname, password);
}, [password, check, term]);
return (
<AppLayout>
<Head>
<title>ํ์๊ฐ์
| NodeBird </title>
</Head>
<Form onFinish={onSubmit}>
<div>
<label htmlFor="user-id">์์ด๋</label>
<br />
<Input name="user-id" value={id} onChange={onChangeId} />
</div>
<div>
<label htmlFor="user-nickname">๋๋ค์</label>
<br />
<Input
name="user-nickname"
value={nickname}
onChange={onChangeNickname}
/>
</div>
<div>
<label htmlFor="user-password">๋น๋ฐ๋ฒํธ</label>
<br />
<Input
name="user-password"
type="password"
value={password}
onChange={onChangePassword}
/>
</div>
<div>
<label htmlFor="user-check">๋น๋ฐ๋ฒํธํ์ธ</label>
<br />
<Input
name="user-check"
type="password"
value={check}
onChange={onChangeCheck}
/>
</div>
{passwordError && (
<PasswordError>๋น๋ฐ๋ฒํธ๊ฐ ๋ง์ง ์์ต๋๋ค.</PasswordError>
)}
<Checkbox name="user-term" checked={term} onChange={onChangeTerm}>
๋์ํฉ๋๋ค.
</Checkbox>
{termError && <div style={{ color: "red" }}>์ฝ๊ด์ ๋์ํด์ฃผ์ธ์</div>}
<div style={{ marginTop: 10 }}>
<Button type="primary" htmlType="submit">
๊ฐ์
</Button>
</div>
</Form>
</AppLayout>
);
}
๊ธธ๊ธด ํ์ง๋ง ์์ฑ๋ณธ๋ ๋ณผ๊น์