diff --git a/.gitignore b/.gitignore index 1437c53..f549c3e 100644 --- a/.gitignore +++ b/.gitignore @@ -32,3 +32,5 @@ yarn-error.log* # vercel .vercel + +.vscode/ \ No newline at end of file diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 0000000..c43b71d --- /dev/null +++ b/.prettierignore @@ -0,0 +1,4 @@ +.next/ +node_modules/ +.vscode/ +.github/ \ No newline at end of file diff --git a/README.md b/README.md index 6a493d9..05f2182 100644 --- a/README.md +++ b/README.md @@ -1 +1,3 @@ # ugra-hackathon_frontend + +Training project to get another members of team used to code style diff --git a/components/ExampleComponent.jsx b/components/ExampleComponent.jsx new file mode 100644 index 0000000..ccd8082 --- /dev/null +++ b/components/ExampleComponent.jsx @@ -0,0 +1,9 @@ +import React from "react"; + +import styles from "styles/exampleComponent.module.css"; + +const ExampleComponent = () => { + return ; +}; + +export default ExampleComponent; diff --git a/components/PowerfulComponent/handlers.js b/components/PowerfulComponent/handlers.js new file mode 100644 index 0000000..537bdc0 --- /dev/null +++ b/components/PowerfulComponent/handlers.js @@ -0,0 +1,11 @@ +// Лучше писать документацию на функции, за это будет респект от менторов +/** + * Increase counter + * @param {SetStateAction} setCounter + */ +const handleCounterClick = (setCounter) => { + return () => setCounter((prev) => prev + 1); // Если используем контекст, тогда замыкаем всё, что нужно внутри обработчика +}; + +// Экспорт лучше делать отдельно, чтобы всегда знать, что мы экспортируем из файла, а что используем внутри (как с public/private методами) +export { handleCounterClick }; diff --git a/components/PowerfulComponent/index.js b/components/PowerfulComponent/index.js new file mode 100644 index 0000000..0fb9493 --- /dev/null +++ b/components/PowerfulComponent/index.js @@ -0,0 +1,26 @@ +import React, { useCallback, useContext } from "react"; + +import { CounterContext } from "context/counterContext"; +import { handleCounterClick } from "./handlers"; // Обработчики событий лучше держать в отдельном файле или использовать кастомные хуки + +/** + * Complex component with counter with context in it + */ +const PowerfulComponent = () => { + const context = useContext(CounterContext); + + console.log(context); + + const handleClick = useCallback(handleCounterClick(context.setCounter), [ + context.setCounter, + ]); + + return ( +
+

{context?.counter}

+ +
+ ); +}; + +export default PowerfulComponent; diff --git a/context/counterContext.js b/context/counterContext.js new file mode 100644 index 0000000..dec904e --- /dev/null +++ b/context/counterContext.js @@ -0,0 +1,22 @@ +import React, { useEffect, useMemo, useState } from "react"; + +const CounterContext = React.createContext(null); + +const initialContext = 0; + +const CounterProvider = ({ children }) => { + const [counter, setCounter] = useState(null); + + useEffect(() => { + // Тут что-то делать для инициализации контекста + setCounter(initialContext); // Например + }, []); + + const value = useMemo(() => ({ counter, setCounter }), [counter]); // На самом деле, в случе нашего проекта это мало повлияет на производительность, но в каком-то туториале советовали так делать, поэтому почему бы и нет + + return ( + {children} + ); +}; + +export { CounterContext, CounterProvider }; diff --git a/hooks/counter.js b/hooks/counter.js new file mode 100644 index 0000000..278c5d9 --- /dev/null +++ b/hooks/counter.js @@ -0,0 +1,21 @@ +import { useState } from "react"; + +// Если функционал можно где-то переиспользовать или если код логики компонента занимает больше 150 строк, стоит разбить его на кастомные хуки и вынести сюда +/** + * Simple counter hook + * @param {number} initialState + */ +const useCounter = (initialState = 0) => { + if (typeof initialState !== "number") + throw new Error("Initial counter state must be a number"); + + const [counter, setCounter] = useState(initialState); + + const increaseCounter = () => { + setCounter((prev) => prev + 1); + }; + + return { counter, increaseCounter }; +}; + +export { useCounter } \ No newline at end of file diff --git a/jsconfig.json b/jsconfig.json new file mode 100644 index 0000000..499ef8b --- /dev/null +++ b/jsconfig.json @@ -0,0 +1,8 @@ +{ + "compilerOptions": { + "module": "esnext", + "target": "es5", + "baseUrl": "." + }, + "exclude": ["node_modules", ".next"] +} diff --git a/pages/_app.tsx b/pages/_app.tsx index 2fc3e07..b88a9af 100644 --- a/pages/_app.tsx +++ b/pages/_app.tsx @@ -1,7 +1,15 @@ -import "../styles/globals.css"; +import React from 'react' + +import "styles/globals.css"; +import { CounterProvider } from "context/counterContext"; function MyApp({ Component, pageProps }) { - return ; + return ( + // Здесь компонент Component оборачиваем провайдеры глобального контекста. Если контекст используется не во всём приложении, а в каком-то определённом компоненте и его дочерних элементах, стоит занести провайдер туда + + + + ); } export default MyApp; diff --git a/pages/counter.tsx b/pages/counter.tsx new file mode 100644 index 0000000..4f3c30a --- /dev/null +++ b/pages/counter.tsx @@ -0,0 +1,15 @@ +import React from "react"; +import { useCounter } from "hooks/counter"; + +const Counter = () => { + const { counter, increaseCounter } = useCounter(); + + return ( +
+

{counter}

+ +
+ ); +}; + +export default Counter \ No newline at end of file diff --git a/pages/index.tsx b/pages/index.tsx index 6ff5373..2d122a4 100644 --- a/pages/index.tsx +++ b/pages/index.tsx @@ -1,3 +1,17 @@ +import React from "react"; +import Link from "next/link"; + +import ExampleComponent from "components/ExampleComponent"; +import PowerfulComponent from "components/PowerfulComponent"; + export default function Home() { - return <>; + return ( + <> + + + + Simplifyed counter + + + ); } diff --git a/styles/exampleComponent.module.css b/styles/exampleComponent.module.css new file mode 100644 index 0000000..01bc332 --- /dev/null +++ b/styles/exampleComponent.module.css @@ -0,0 +1,6 @@ +/* Благодаря использованию css-modules можно использовать одни и те же названия классов + в разных компонентах и ничего нам за это не будет, ибо при сборке к ним добавятся хеши */ +.button { + background-color: red; + color: white; +} diff --git a/tsconfig.json b/tsconfig.json index 93a83a4..1ceb1ea 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -12,7 +12,8 @@ "moduleResolution": "node", "resolveJsonModule": true, "isolatedModules": true, - "jsx": "preserve" + "jsx": "preserve", + "baseUrl": "." }, "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"], "exclude": ["node_modules"]