From 4555185495966a9e11a102373c8b7b46b0dd396b Mon Sep 17 00:00:00 2001 From: suhareevai Date: Mon, 12 Aug 2024 21:28:03 +0300 Subject: [PATCH 1/2] React patterns - refactoring --- my-app/src/App.tsx | 43 +++++-------------- my-app/src/client/api.ts | 16 +++++++ my-app/src/components/button/index.tsx | 4 +- my-app/src/components/button/style.scss | 13 ++++-- my-app/src/components/button/types.ts | 5 +++ .../src/components/buttonWithLabel/index.tsx | 10 +++-- .../src/components/buttonWithLabel/style.scss | 14 +++--- .../src/components/buttonWithLabel/types.ts | 6 +++ my-app/src/components/form/index.tsx | 24 +++-------- my-app/src/components/form/style.scss | 17 +------- my-app/src/components/form/types.ts | 5 +++ my-app/src/components/memberCard/index.tsx | 8 ++-- my-app/src/components/tabs/index.tsx | 12 +++--- my-app/src/components/tabs/style.scss | 7 +++ my-app/src/components/tabs/types.ts | 4 ++ my-app/src/components/userList/UserList.tsx | 24 +++++++++++ my-app/src/hooks/useUsers.ts | 23 ++++++++++ 17 files changed, 145 insertions(+), 90 deletions(-) create mode 100644 my-app/src/client/api.ts create mode 100644 my-app/src/components/button/types.ts create mode 100644 my-app/src/components/buttonWithLabel/types.ts create mode 100644 my-app/src/components/form/types.ts create mode 100644 my-app/src/components/tabs/style.scss create mode 100644 my-app/src/components/tabs/types.ts create mode 100644 my-app/src/components/userList/UserList.tsx create mode 100644 my-app/src/hooks/useUsers.ts diff --git a/my-app/src/App.tsx b/my-app/src/App.tsx index 5a4830a..4b4c99e 100644 --- a/my-app/src/App.tsx +++ b/my-app/src/App.tsx @@ -1,48 +1,25 @@ import "./App.scss"; import { MemberCard } from "../src/components/memberCard"; -import { useEffect, useState } from "react"; +import {useState} from "react"; import { UserProps } from "./components/memberCard/types"; -import { ButtonWithLabel } from "./components/buttonWithLabel"; import Form from "./components/form"; import { Tabs } from "./components/tabs"; +import {UserList} from "./components/userList/UserList"; export default function App() { - const [users, setUsers] = useState([]); - const [moreUsers, setMoreUsers] = useState([]); - const [addedUser, setAddedUser] = useState(null); const [tabForm, setTabForm] = useState(true); - - useEffect(() => { - fetch('https://jsonplaceholder.typicode.com/users') - .then((response) => response.json()) - .then((res) => setUsers(res)); - }, []); - - const onButtonClick = () => { - fetch('https://jsonplaceholder.typicode.com/users') - .then((response) => response.json()) - .then((res) => setMoreUsers(res)); - }; - - const handleUserAddition = (user: UserProps) => { - setAddedUser(user); -}; + const [addedUser, setAddedUser] = useState(null); + + const onUserAddition = (user : UserProps) => { + setAddedUser(user); + } return (
- {!tabForm && users.map((user) => )} - {!tabForm && moreUsers.map((user) => )} - {!tabForm && more users} - {tabForm &&
} - {addedUser && ( - - )} + {!tabForm && } + {tabForm && } + {addedUser && ()}
); } diff --git a/my-app/src/client/api.ts b/my-app/src/client/api.ts new file mode 100644 index 0000000..5c02fff --- /dev/null +++ b/my-app/src/client/api.ts @@ -0,0 +1,16 @@ +const apiUrl = "https://jsonplaceholder.typicode.com/users"; + +export const getUsers = fetch(apiUrl) + .then((response) => response.json()); + +export const addUser = (username: string, phone: string, website: string) => fetch(apiUrl, { + method: 'POST', + body: JSON.stringify({ + username, + phone, + website, + }), + headers: { + 'Content-type': 'application/json; charset=UTF-8', + }, +}).then((response) => response.json()); \ No newline at end of file diff --git a/my-app/src/components/button/index.tsx b/my-app/src/components/button/index.tsx index c986301..38a85af 100644 --- a/my-app/src/components/button/index.tsx +++ b/my-app/src/components/button/index.tsx @@ -1,6 +1,8 @@ import "./style.scss"; +import {FC} from "react"; +import {ButtonProps} from "./types"; -export const Button = ({ onClick, children }: {onClick: () => void, children?: string}) => { +export const Button : FC = ({ onClick, children }) => { return ( diff --git a/my-app/src/components/button/style.scss b/my-app/src/components/button/style.scss index 7463d18..90471a7 100644 --- a/my-app/src/components/button/style.scss +++ b/my-app/src/components/button/style.scss @@ -1,6 +1,13 @@ .button { - padding: 10px; - border-radius: 5px; - background-color: antiquewhite; + margin-top: 10px; + padding: 8px 16px; + border: none; + border-radius: 4px; + background-color: #007bff; + color: #fff; cursor: pointer; +} + +button:hover { + background-color: #0056b3; } \ No newline at end of file diff --git a/my-app/src/components/button/types.ts b/my-app/src/components/button/types.ts new file mode 100644 index 0000000..cf9fdf6 --- /dev/null +++ b/my-app/src/components/button/types.ts @@ -0,0 +1,5 @@ +export interface ButtonProps +{ + onClick: () => void, + children?: string +} \ No newline at end of file diff --git a/my-app/src/components/buttonWithLabel/index.tsx b/my-app/src/components/buttonWithLabel/index.tsx index 4401bc4..48a63d0 100644 --- a/my-app/src/components/buttonWithLabel/index.tsx +++ b/my-app/src/components/buttonWithLabel/index.tsx @@ -1,12 +1,14 @@ import { Button } from "../button"; import "./style.scss"; +import {FC} from "react"; +import {ButtonWithLabelProps} from "./types"; -export const ButtonWithLabel = ({ onClick, children }: { onClick: () => void, children: string }) => { - const text =

нажми меня!

; +export const ButtonWithLabel : FC = (props) => { + const {label, ...restProps} = props; return (
- {text} - +

{label}

+
); }; \ No newline at end of file diff --git a/my-app/src/components/buttonWithLabel/style.scss b/my-app/src/components/buttonWithLabel/style.scss index 614b4db..18de3cb 100644 --- a/my-app/src/components/buttonWithLabel/style.scss +++ b/my-app/src/components/buttonWithLabel/style.scss @@ -1,7 +1,11 @@ .button-with-label { - display: flex; - flex-direction: column; - gap: 5px; - justify-content: center; - align-items: center; + display: flex; + flex-direction: column; + gap: 5px; + justify-content: center; + align-items: center; + + p { + margin-right: 5px; + } } \ No newline at end of file diff --git a/my-app/src/components/buttonWithLabel/types.ts b/my-app/src/components/buttonWithLabel/types.ts new file mode 100644 index 0000000..5714a9f --- /dev/null +++ b/my-app/src/components/buttonWithLabel/types.ts @@ -0,0 +1,6 @@ +export interface ButtonWithLabelProps +{ + onClick: () => void, + children: string, + label: string +} \ No newline at end of file diff --git a/my-app/src/components/form/index.tsx b/my-app/src/components/form/index.tsx index 08e5b8b..7643ebb 100644 --- a/my-app/src/components/form/index.tsx +++ b/my-app/src/components/form/index.tsx @@ -1,14 +1,13 @@ import React, { useState, FormEvent, ChangeEvent } from 'react'; import './style.scss'; - -interface FormProps { - onUserAddition: (user: any) => void; // Принимаем функцию для обновления состояния верхнего компонента -} +import {FormProps} from "./types"; +import {useUsers} from "../../hooks/useUsers"; const Form: React.FC = ({ onUserAddition }) => { const [username, setUsername] = useState(''); const [phone, setPhone] = useState(''); const [website, setWebsite] = useState(''); + const {setUser} = useUsers(); const handleUsernameChange = (event: ChangeEvent) => { setUsername(event.target.value); @@ -24,21 +23,8 @@ const Form: React.FC = ({ onUserAddition }) => { const handleSubmit = (event: FormEvent) => { event.preventDefault(); - - fetch('https://jsonplaceholder.typicode.com/users', { - method: 'POST', - body: JSON.stringify({ - username, - phone, - website, - }), - headers: { - 'Content-type': 'application/json; charset=UTF-8', - }, - }) - .then((response) => response.json()) - .then((user) => onUserAddition(user)); - }; + setUser(username, phone, website).then((user) => onUserAddition(user)); + } return ( diff --git a/my-app/src/components/form/style.scss b/my-app/src/components/form/style.scss index f00c4b1..7927523 100644 --- a/my-app/src/components/form/style.scss +++ b/my-app/src/components/form/style.scss @@ -14,19 +14,4 @@ margin-top: 5px; border-radius: 4px; border: 1px solid #ccc; - } - - .button { - margin-top: 10px; - padding: 8px 16px; - border: none; - border-radius: 4px; - background-color: #007bff; - color: #fff; - cursor: pointer; - } - - button:hover { - background-color: #0056b3; - } - \ No newline at end of file + } \ No newline at end of file diff --git a/my-app/src/components/form/types.ts b/my-app/src/components/form/types.ts new file mode 100644 index 0000000..d9dbbd2 --- /dev/null +++ b/my-app/src/components/form/types.ts @@ -0,0 +1,5 @@ +import {UserProps} from "../memberCard/types"; + +export interface FormProps { + onUserAddition: (user : UserProps) => void; // Принимаем функцию для обновления состояния верхнего компонента +} \ No newline at end of file diff --git a/my-app/src/components/memberCard/index.tsx b/my-app/src/components/memberCard/index.tsx index d4e3a95..7f643bd 100644 --- a/my-app/src/components/memberCard/index.tsx +++ b/my-app/src/components/memberCard/index.tsx @@ -1,14 +1,14 @@ import { FC } from "react"; import "./style.scss"; - import { UserProps } from "./types"; import { CardInfo } from "./parts/cardInfo"; -export const MemberCard: FC = ({ name, username, phone, website }) => { +export const MemberCard: FC = (props) => { + const {name, ...restProps} = props; return (

{name}

- +
); -}; +}; \ No newline at end of file diff --git a/my-app/src/components/tabs/index.tsx b/my-app/src/components/tabs/index.tsx index 18693d6..4d6cd7b 100644 --- a/my-app/src/components/tabs/index.tsx +++ b/my-app/src/components/tabs/index.tsx @@ -1,11 +1,13 @@ import { Button } from "../button"; - -export const Tabs = ({ onChange }: { onChange: (tab: boolean) => void }) => { +import "./style.scss"; +import {FC} from "react"; +import {TabsProps} from "./types"; +export const Tabs : FC = ({ onChange }) => { return ( -
- - +
+ +
); }; \ No newline at end of file diff --git a/my-app/src/components/tabs/style.scss b/my-app/src/components/tabs/style.scss new file mode 100644 index 0000000..448aa82 --- /dev/null +++ b/my-app/src/components/tabs/style.scss @@ -0,0 +1,7 @@ +.tab { + width: 100%; + display: flex; + gap: 15px; + justify-content: center; + margin-bottom: 20px +} \ No newline at end of file diff --git a/my-app/src/components/tabs/types.ts b/my-app/src/components/tabs/types.ts new file mode 100644 index 0000000..0a62dda --- /dev/null +++ b/my-app/src/components/tabs/types.ts @@ -0,0 +1,4 @@ +export interface TabsProps +{ + onChange: (tab: boolean) => void +} diff --git a/my-app/src/components/userList/UserList.tsx b/my-app/src/components/userList/UserList.tsx new file mode 100644 index 0000000..bade18b --- /dev/null +++ b/my-app/src/components/userList/UserList.tsx @@ -0,0 +1,24 @@ +import {MemberCard} from "../memberCard"; +import {ButtonWithLabel} from "../buttonWithLabel"; +import {useUsers} from "../../hooks/useUsers"; +import {useEffect} from "react"; + +export const UserList = () => { + const {users, setUserList} = useUsers(); + useEffect(() => { + setUserList(); + }, []); + + const onButtonClick = () => { + setUserList(); + }; + + return ( + <> + {users.map((user) => { + return + })} + more users + + ); +}; \ No newline at end of file diff --git a/my-app/src/hooks/useUsers.ts b/my-app/src/hooks/useUsers.ts new file mode 100644 index 0000000..74e93d0 --- /dev/null +++ b/my-app/src/hooks/useUsers.ts @@ -0,0 +1,23 @@ +import {useState} from "react"; +import {addUser, getUsers} from "../client/api"; +import {UserProps} from "../components/memberCard/types"; + +export const useUsers = () => { + const [users, setUsers] = useState([]); + + const setUserList = () => { + getUsers.then((data : UserProps[]) => { + setUsers(data) + }); + } + + const setUser = (username: string, phone: string, website: string) => { + return addUser(username, phone, website) + } + + return { + users, + setUser, + setUserList + } +} \ No newline at end of file From c2bf9e8da53ed10519302dfdf1fcfc2628d912a9 Mon Sep 17 00:00:00 2001 From: suhareevai Date: Tue, 20 Aug 2024 20:15:12 +0300 Subject: [PATCH 2/2] =?UTF-8?q?React=20patterns=20-=20=D0=BF=D1=80=D0=B0?= =?UTF-8?q?=D0=B2=D0=BA=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- my-app/src/components/button/types.ts | 3 +-- my-app/src/components/buttonWithLabel/index.tsx | 3 +-- my-app/src/components/buttonWithLabel/types.ts | 3 +-- my-app/src/components/form/index.tsx | 2 +- my-app/src/components/memberCard/index.tsx | 3 +-- my-app/src/components/memberCard/types.ts | 3 +-- my-app/src/components/tabs/types.ts | 5 ++--- 7 files changed, 8 insertions(+), 14 deletions(-) diff --git a/my-app/src/components/button/types.ts b/my-app/src/components/button/types.ts index cf9fdf6..426cd3d 100644 --- a/my-app/src/components/button/types.ts +++ b/my-app/src/components/button/types.ts @@ -1,5 +1,4 @@ -export interface ButtonProps -{ +export interface ButtonProps { onClick: () => void, children?: string } \ No newline at end of file diff --git a/my-app/src/components/buttonWithLabel/index.tsx b/my-app/src/components/buttonWithLabel/index.tsx index 48a63d0..4d1ec49 100644 --- a/my-app/src/components/buttonWithLabel/index.tsx +++ b/my-app/src/components/buttonWithLabel/index.tsx @@ -3,8 +3,7 @@ import "./style.scss"; import {FC} from "react"; import {ButtonWithLabelProps} from "./types"; -export const ButtonWithLabel : FC = (props) => { - const {label, ...restProps} = props; +export const ButtonWithLabel : FC = ({label, ...restProps}) => { return (

{label}

diff --git a/my-app/src/components/buttonWithLabel/types.ts b/my-app/src/components/buttonWithLabel/types.ts index 5714a9f..3f59adf 100644 --- a/my-app/src/components/buttonWithLabel/types.ts +++ b/my-app/src/components/buttonWithLabel/types.ts @@ -1,5 +1,4 @@ -export interface ButtonWithLabelProps -{ +export interface ButtonWithLabelProps { onClick: () => void, children: string, label: string diff --git a/my-app/src/components/form/index.tsx b/my-app/src/components/form/index.tsx index 7643ebb..c905fc9 100644 --- a/my-app/src/components/form/index.tsx +++ b/my-app/src/components/form/index.tsx @@ -51,4 +51,4 @@ const Form: React.FC = ({ onUserAddition }) => { ); }; -export default Form; +export default Form; \ No newline at end of file diff --git a/my-app/src/components/memberCard/index.tsx b/my-app/src/components/memberCard/index.tsx index 7f643bd..0ea59e5 100644 --- a/my-app/src/components/memberCard/index.tsx +++ b/my-app/src/components/memberCard/index.tsx @@ -3,8 +3,7 @@ import "./style.scss"; import { UserProps } from "./types"; import { CardInfo } from "./parts/cardInfo"; -export const MemberCard: FC = (props) => { - const {name, ...restProps} = props; +export const MemberCard: FC = ({name, ...restProps}) => { return (

{name}

diff --git a/my-app/src/components/memberCard/types.ts b/my-app/src/components/memberCard/types.ts index 2cb301f..35fcbdd 100644 --- a/my-app/src/components/memberCard/types.ts +++ b/my-app/src/components/memberCard/types.ts @@ -3,5 +3,4 @@ export interface UserProps { username: string; phone: string; website: string; - } - \ No newline at end of file +} \ No newline at end of file diff --git a/my-app/src/components/tabs/types.ts b/my-app/src/components/tabs/types.ts index 0a62dda..fba894c 100644 --- a/my-app/src/components/tabs/types.ts +++ b/my-app/src/components/tabs/types.ts @@ -1,4 +1,3 @@ -export interface TabsProps -{ +export interface TabsProps { onChange: (tab: boolean) => void -} +} \ No newline at end of file