@kirilljs эй, че сразу бить то…
Jspi
Сообщения
-
JavaScript мемы -
Программисты раньше и сейчас -
Программисты c GPT и без -
Проблема с дублированием данных при вызове return вместо reply.send - FastifyПользователь @kirilljs написал в Проблема с дублированием данных при вызове return вместо reply.send - Fastify:
const userService = new UserService();
Лучше не создавать сервис каждый раз в функции, это лишние затраты
-
Проблема с дублированием данных при вызове return вместо reply.send - FastifyВо первых ты описал
createNewUser()
как асинхронную функцию, и она у тебя ничего не возвращает, а также ты нигде await не используешь, у тебя тогда и try не будет ничего ловитьПопробуй вместо
userRepository.save(user)
написать асинхронную функцию простую (например таймер), и сделай там console.log(), посмотри сколько сообщений выдаст, сделай такой дебаггинг -
pm2 автоматический restart при перезагрузки сервераПользователь @kirilljs написал в pm2 автоматический restart при перезагрузки сервера:
Далее нам необходимо запустить скрипт startup, который как раз отвечает за автоматический запуск pm2 после перезагрузки сервера:
Поправка: команда startup просто показывает команду, при исполнении которой сервис pm2 будет загружать автоматически сохраненные процессы
-
PageProps Type Errors in Next.js. Type '{ slug: string; }' is missing the following properties from type 'Promise<any>'После обновления Next js до 15 версии, в динамических маршрутах разработчики некоторые изменения, что приведет к ошибкам при сборке проекта.
пример:
Type error: Type 'Props' does not satisfy the constraint 'PageProps'. Types of property 'params' are incompatible. Type '{ slug: string; }' is missing the following properties from type 'Promise<any>': then, catch, finally, [Symbol.toStringTag]
Разработчики сделали динамические параметры асинхронными, поэтому нужно будет поменять типы, и получать их мы должны, например, через
await
до 15 версии:
// СТАРЫЙ КОД type Props = { params: { slug: string; }; }; export async function generateMetadata({ params: { slug } }: Props) { const { category } = await fetchData(slug); ... } } export default async function Page({ params: { slug } }: Props) { const data = await fetchData(slug); ... }
после 15 версии:
// НОВЫЙ КОД type Props = { params: Promise<{ slug: string; }>; }; export async function generateMetadata(props: Props) { const { slug } = await props.params; const { category } = await fetchData(slug); ... } } export default async function Page(props: Props) { const { slug } = await props.params; const data = await fetchData(slug); ... }
-
Оптимизация React js приложений. Использование функции debounde()Пользователь @kirilljs написал в Оптимизация React js приложений. Использование функции debounde():
И почему onInput, а не onChange
onInput отлавливает все изменения значения в
<input />
, даже такие как нажатие клавиш и вставку текста, поэтому он предпочтительнее в данном случае -
Оптимизация React js приложений. Использование функции debounde()Пользователь @kirilljs написал в Оптимизация React js приложений. Использование функции debounde():
Простыми словами, мы колбэчим submitHandler через debounceHandler то как оно должно быть по спецификации JS
не понял вопроса, напомню, чтчо тут не используется никаких форм, фактически все обработчики привязаны к onInput событию, функция
debounce()
- самописная -
Оптимизация React js приложений. Использование функции debounde()Допустим мы имеем очень абстрактный компонент, который имеет поле ввода текста, кнопку отправки этого текста на сервер, и сообщение о состоянии отправки данных на сервер
Пример кода
// функция иммитации запроса на сервер function fakeFetch(val: string) { return new Promise<string>(function (resolve) { setTimeout(function () { resolve(`Сервер получил сообщение: ${val}`); }, 1000); }); } // самый простой пример компонента function App() { const [val, setVal] = useState(''); const [response, setResponse] = useState(''); const inputHandler = (e: React.ChangeEvent<HTMLInputElement>) => { setVal(e.target.value); setResponse(''); }; const submitHandler = async () => { setVal(''); setResponse('отправка ...'); const resp = await fakeFetch(val); setResponse(resp); }; return ( <> <input type="text" value={val} onInput={inputHandler} /> <button onClick={submitHandler}>Отправить</button> <p>{response}</p> </> ); }
Теперь перед нами встала задача заменить поведение: отправлять данные не по кнопке, а автоматически. Однако мы не может просто так повесить функцию в обработчик inputHandler(), мало того что он будет неоправданно часто отправлять запросы на сервер, так еще и будет сбивать значение
val
. Но если мы добавить функциюdebounce()
, то она решит эти вопросы.Функция debounce()
debounce() - это функция-обертка, которая ограничивает число выполнений переданной в нее функции, некоторым промежутком времени. Если точнее, то, пока промежуток времени не прошел, то зарегистрированная функция не будет исполнятся, а пока она не исполнилась, новый вызов функции будет замещать старый, исключая повторное выполнение.
пример:
function debounce(func, delay: number) { let timeoutId: number; return (...args) => { clearTimeout(timeoutId); timeoutId = setTimeout(() => func(...args), delay); }; }
Как правильно использовать в React компоненте
function App() { const [val, setVal] = useState(''); const [response, setResponse] = useState(''); const inputHandler = (e: React.ChangeEvent<HTMLInputElement>) => { setVal(e.target.value); setResponse(''); debounceHandler(); }; const submitHandler = useCallback(async () => { setResponse('отправка ...'); const resp = await fakeFetch(val); setVal(''); setResponse(resp); }, []); const debounceHandler = useMemo(() => { return debounce(submitHandler, 800); }, [submitHandler]); return ( <> <input type="text" value={val} onInput={inputHandler} /> {/* <button onClick={submitHandler}>Отправить</button> */} <p>{response}</p> </> ); }
При изменении стейта функциональный компонент вызывает свою функцию каждый раз, и без мемоизации мы бы получали каждый раз новый обработчик
debounceHandler()
иsubmitHandler()
. Но для того чтобы все работало нам необходимо передать одну функцию в debounce один раз!Поэтому мемоизируем submitHandler() через
useCallback
(линтер обычно потребует указатьsubmitHandler
как зависимостьdebounceHandler
) и саму функциюdebounceHandler()
вuseMemo
, (т.к debounce() возвращает функцию) -
Создание пользователя и базы данных, настройка доступов, установка пароляСначала необходимо войти в систему как суперпользователь базы данных на сервере postgresql. Опять же, самый простой способ подключиться в качестве пользователя postgres — это перейти на пользователя postgres unix на сервере базы данных с помощью команды su следующим образом:
$ su postgres
Далее заходим в среду PostgreSQL
$ psql
В случае успеха вы должны увидеть следующее:
postgres=#
В командной строке PostgreSQL создайте базу данных, имя пользователя и пароль, а затем предоставьте весь доступ этому новому пользователю. Например:
CREATE DATABASE {database}; CREATE USER {user} WITH PASSWORD 'password'; GRANT ALL ON DATABASE {database} TO {user};
выходим из среды PostgreSQL
$ \q
профит!
-
Ошибка: permission denied for schema public (Postgresql 15)Если вылезла подобная ошибка:
driverError: error: permission denied for schema public
PostgreSQL версии 15+ может выдать сообщение об ошибке, что у вас нет разрешения на создание чего-либо внутри общедоступной схемы, если заранее явно не указать, кому разрешено это делать.
Нам нужно явно предоставить разрешения пользователю.
- Сначала заходим в cli Нашей СУБД
sudo su postgres psql -d {database}
- далее назначаем права
GRANT ALL ON SCHEMA public TO {user};
- выходим
\q
{database}
- имя базы данных
{user}
- имя пользователя -
Zod + Nestjs (вместо сlass-validator)@Manul поэтому и приходится велосипедить)
-
Vue.js и React — необычное сравнение -
JavaScript для самых маленьких. Часть #1 -
Zod + Nestjs (вместо сlass-validator)Очень удобно внедрять проверку данных запроса декларативно, в контроллерах. Так и учит нас официальная документация nestjs, и для этого нам необходима библиотека class-validator
Но многим не нравится обмазываться декораторами, особенно когда их много решение кажется очень сомнительным:
class CreateCompanyDto implements Dto { @IsString({message: 'Must be text format'}) @MinLength(2, { message: "Must have at least 2 characters" }) @MaxLength(20, { message: "Can't be longer than 20 characters" }) @IsDefined({ message: 'Must specify a receiver' }) public name!: string; @MaxLength(253, { message: "Can't be longer than 253 characters" }) @IsFQDN({}, {message: 'Must be a valid domain name'}) @IsDefined({ message: 'Must specify a domain' }) public domain!: string; @MaxLength(30, { message: "Can't be longer than 30 characters" }) @IsString({message: 'Must be text format'}) @IsDefined({ message: 'Must specify a company size' }) public size!: string; @IsPhoneNumber(null, {message: 'Must be a valid phone number'}) @IsDefined({ message: 'Must specify a phone number' }) public contact!: string; }
Zod - это удобная альтернатива библиотеке проверки классов для проверки тела запроса.
Пример кода
Итак поехали…
Создаем схему
import { z } from "zod"; export const createProductShema = z.object({ title: z.string(), text: z.string(), active: z.boolean(), }); type CreateProductDtoType = z.infer<typeof createProductShema>; // или вместо типа можем использовать интерфейс export interface CreateProductDto extends CreateProductDtoType {}
z.infer() позволит нам получить тип для данных, которые будем валидировать
далее создаем Pipe
@Injectable() export class ZodPipe implements PipeTransform { constructor(private readonly schema: any) {} transform(value: any, metadata: ArgumentMetadata) { this.schema.parse(value); return value; } }
и обмазываем наш контролер ранее созданным пайпом
@Controller() export class AppController { constructor(private readonly productUseCaseService: ProductUseCaseService) {} @Post() createProduct(@Body(new ZodPipe(schema)) body: CreateProductDto) { return this.productUseCaseService.create(body); } }
Ну и для того, чтобы мы отлавливали ошибки валидации, и формировали ответ запроса как нам нужно
напишем фильтр и подключим его@Catch(ZodError) export class ZodFilter<T extends ZodError> implements ExceptionFilter { catch(exception: T, host: ArgumentsHost) { const ctx = host.switchToHttp(); const response = ctx.getResponse(); const status = 400; response.status(status).json({ errors: exception.errors, message: exception.message, statusCode: status, }); } }
async function bootstrap() { const app = await NestFactory.create(AppModule); app.useGlobalFilters(new ZodFilter()); await app.listen(3000); }
Такая схема кажется гибче, и вообще zod закрывает проблемные места typescript связанные с отсутствием проверки типов в runtime
-
Typescript: Union Type vs EnumЧасто объединенные типы
Union Type
и перечисляемый типEnum
- это онди из способов обеспечения типобезопасности кода, в частности типизация ограниченного списка каких либо значений.Они также оба хорошо работают с современными IDE предлагая в подсказках отфильтрованные значения.
Но бывает задаешься вопросом: что лучше использовать в той или иной ситуации?
Разница в размере кода
Объединенные типы не будут создавать какой либо дополнительный код.
Вот Простой пример:Версия с Union Type
type VehicleTypeUnion = 'SUV' | 'SEDAN' | 'TRUCK'; const a: VehicleTypeUnion = 'SUV'
->
"use strict"; const a = 'SUV';
Версия с Enum
enum VehicleTypeEnum { SUV, SEDAN, TRUCK, } const b: VehicleTypeEnum = VehicleTypeEnum.SUV
->
var VehicleTypeEnum; (function (VehicleTypeEnum) { VehicleTypeEnum[VehicleTypeEnum["SUV"] = 0] = "SUV"; VehicleTypeEnum[VehicleTypeEnum["SEDAN"] = 1] = "SEDAN"; VehicleTypeEnum[VehicleTypeEnum["TRUCK"] = 2] = "TRUCK"; })(VehicleTypeEnum || (VehicleTypeEnum = {})); const b = VehicleTypeEnum.SUV;
Разные типы в списке значений
перечисляемый тип обычно описывается в виде числовых значений или в виде строковых.
// список enum VehicleType1 { SUV, SEDAN, TRUCK, BUS, MOTORCYCLE } // эквивалентный список enum VehicleType2{ SUV = 0, SEDAN = 1, TRUCK = 2, BUS = 3, MOTORCYCLE = 4 } // список со строковыми значениями enum VehicleType3{ SUV = 'SUV', SEDAN = 'SEDAN', TRUCK = 'TRUCK', BUS = 'BUS', MOTORCYCLE = 'MOTORCYCLE' }
->
"use strict"; // перечисляемый тип var VehicleType1; (function (VehicleType1) { VehicleType1[VehicleType1["SUV"] = 0] = "SUV"; VehicleType1[VehicleType1["SEDAN"] = 1] = "SEDAN"; VehicleType1[VehicleType1["TRUCK"] = 2] = "TRUCK"; VehicleType1[VehicleType1["BUS"] = 3] = "BUS"; VehicleType1[VehicleType1["MOTORCYCLE"] = 4] = "MOTORCYCLE"; })(VehicleType1 || (VehicleType1 = {})); // эквивалентный тип var VehicleType2; (function (VehicleType2) { VehicleType2[VehicleType2["SUV"] = 0] = "SUV"; VehicleType2[VehicleType2["SEDAN"] = 1] = "SEDAN"; VehicleType2[VehicleType2["TRUCK"] = 2] = "TRUCK"; VehicleType2[VehicleType2["BUS"] = 3] = "BUS"; VehicleType2[VehicleType2["MOTORCYCLE"] = 4] = "MOTORCYCLE"; })(VehicleType2 || (VehicleType2 = {})); // тип со строковыми значениями var VehicleType3; (function (VehicleType3) { VehicleType3["SUV"] = "SUV"; VehicleType3["SEDAN"] = "SEDAN"; VehicleType3["TRUCK"] = "TRUCK"; VehicleType3["BUS"] = "BUS"; VehicleType3["MOTORCYCLE"] = "MOTORCYCLE"; })(VehicleType3 || (VehicleType3 = {}));
Первый тип мы описали без инициализирующих значений, его значения инициализируются автоматически, в зависимости от порядка, поэтому порядок значений менять опасно!
Это также накладывает ограничение, что мы не можем использовать тип с проинициализированными значениями и без:
enum VehicleType { SUV = 'SUV', SEDAN = 'SEDAN', TRUCK = 'TRUCK', BUS = 'BUS', MOTORCYCLE }
Выведет ошибку
error TS1061: Enum member must have initializer.
Вам придется описать тип так:
enum VehicleType { SUV = 'SUV', SEDAN = 'SEDAN', TRUCK = 'TRUCK', BUS = 'BUS', MOTORCYCLE = 0, }
Union Type
Тут вы можете создавать объединения с другими типами значений, отличными от строк:
type VehicleType = 'SUV' | 'SEDAN' | 'TRUCK' | 0 | [];
Это дает вам дополнительную гибкость в определении типов. Однако такая дополнительная гибкость может привести к неожиданному поведению в коде при отсутствии четкого понимания типа переменной, которая может быть строкой, или числом, или массивом объектов и т.д.
Перебор значений
Перечисления - это объекты, где каждому ключу свойства может быть автоматически присвоено значение или строка на случай, если мы определим значение вручную. Следовательно, вы можете повторять значения свойств точно так же, как и любой другой объект:
export enum VehicleType { SUV = 'SUV', SEDAN = 'SEDAN', TRUCK = 'TRUCK', BUS = 'BUS', MOTORCYCLE = 'MOTORCYCLE' } for (const type in VehicleType) { console.log(type); } Object.keys(VehicleType).forEach((key) => { console.log('key ', key); })
Попытка сделать что-то подобное с union types приведет к ошибке при попытке выполнения кода
type VehicleType = 'SUV' | 'SEDAN' | 'TRUCK' | 'BUS' | 'MOTORCYCLE'; for (const type in VehicleType) { // my logic in here console.log(type); } Object.keys(VehicleType).forEach((key) => { console.log('key ', key); })
error TS2693: 'VehicleType' only refers to a type, but is being used as a value here.
Вывод
Если вам нужно будет выполнять итерации по набору значений, лучше всего использовать
enums
, но вы тем самым пожертвуете размером собранного кода. -
Vue.js и React — необычное сравнениеС того момента, как я начал изучать React, он показался глотком свежего воздуха в мире фронтенда.
Я могу создавать красивые пользовательские интерфейсы только с помощью JavaScript? Внезапно у меня появилась мощь JavaScript внутри HTML и CSS?
Мне очень понравилось. Все было прекрасно.
Я пользовался этим инструментом в течение многих лет, но не мог удержаться от наблюдения за ажиотажем вокруг Vue.js Судя по всему, каждый разработчик, который его использует, очень любит его!
Несколько месяцев назад я запустил Vue в коммерческом проекте и полностью ушел с React.
Но эти фреймворки — всего лишь инструменты; Мы никогда не должны принимать строгие карьерные решения, основываясь на них.
Это фронтенд-мир — все инструменты скоро исчезнут; Новые придут быстро.
Теперь, после огромного опыта во фронтенд-разработке и фреймворках, таких как Angular.js Vue.js, React и Ember.js, позвольте мне объяснить, почему я считаю Vue.js лучшим.
Одно очень простое приложение
Сегодня мы создаем очень простое приложение как на React, так и на Vue.js. Выглядит это примерно так:
Давайте углубимся в код. Реагируйте, вы на первом месте. Это проект, созданный с помощью ; Здесь я немного видоизменил.
create-react-appApp.js
import { useState } from 'react'; function App() { const [isMagicalAnswerVisible, setIsMagicalAnswerVisible] = useState(false) return ( <div className="App"> <p className="magicalQuestion"> Which FE framework is the best? </p> <button className="magicalButton" onClick={() => setIsMagicalAnswerVisible(true)}> Find out! </button> {isMagicalAnswerVisible && <p className="magicalAnswer"> .....what is life? </p>} </div> ); } export default App;
Я хорошо знаю React, поэтому могу во всем этом разобраться. Но давайте предположим, что я ничего не знаю о React — только кое-что о разработке в вебе в целом.
Зная это, я хочу знать, что будет отображаться на экране. Когда я смотрю на браузер, я вижу там только стилизованные HTML-элементы. Не JavaScript.
А здесь — все на JavaScript! Как узнать, что на самом деле будет отображаться на экране?
Я вижу, что это возвращает некоторый код, похожий на HTML, но это не HTML. Что это?
function App()
Хорошо. Я предполагаю, что эта штука будет рендериться.
Что такое ? Почему я не могу просто использовать
class
?onClick={() => setIsMagicalAnswerVisible(true)}
почему я должен это делать, неужели я не могу просто сделать? О, теперь я получаю некоторые ошибки. Я верну стрелочную функцию, хотя и не знаю почемуonClick={setIsMagicalAnswerVisible(true)}
{isMagicalAnswerVisible && <p className=”magicalAnswer”>…..what is life?</p>}
Что это? Что там с фигурными скобками? Что, оператор JS здесь. будет рендерить, еслиisMagicalAnswerVisible === true
?Представьте себе огромный компонент. Я хочу видеть то, что я увижу на экране. Но я не могу, потому что мне приходится прокручивать первые 100 строк кода, чтобы найти оператор.return
Я доверяю именованию функций. Я верю, что они делают то, что говорят. Я не хочу сначала вдаваться в детали реализации.
Что Vue.js может предложить
<template> <p class="magical-question"> Which FE framework is the best? </p> <button class="magical-button" @click="findOutMoreAboutThatMagicalFramework"> Find out! </button> <p v-if="isMagicalAnswerVisible" class="magical-answer"> .....what is life? </p> </template> <script> export default { name: 'App', data() { return { isMagicalAnswerVisible: false } }, methods: { findOutMoreAboutThatMagicalFramework() { this.isMagicalAnswerVisible = true } } } </script>
Хм, что я здесь вижу? Ох уж этот шаблон! Думаю, я увижу этот шаблон на экране.
О, хорошо, здесь. Это HTML-файл?
class
Хм, вот , а также . Поначалу это звучит немного странно, но на самом деле даже для разрабочкика с небольшим опытом это должно быть очевидно
@click
,v-if
И это так просто.
data()
; Что это? Мне нужно будет погуглить. О, это просто состояние компонента.methods
? Довольно просто.Я точно вижу, что будет рендериться первым. Я вижу что-то, похожее на HTML.
Я хочу стилизовать свой компонент. Что мне нужно сделать? Я предполагаю, что это то же самое, что и в HTML; Я просто добавлю тег в нижнюю часть файла.
И это работает!
Кривая обучения React может быть огромной, особенно если вы имеете дело с более сложными вещами. Помните времена, когда еще не было Хуков? Так много Render Props, Higher-Order Components и куча других вещей.
Как насчет этого? Я знаю очень многих React-разработчиков, которые понятия не имеют, что происходит за кулисами.this.handleClick = this.handleClick.bind(this)
С другой стороны, с Vue.js все так просто. Это похоже на обновленную версию HTML.
Я так много работал с Vue.js за последние пару месяцев, и количество разочарований минимально.
Я могу сосредоточиться только на реальной проблеме, а не на фактической реализации.
Я все время задаюсь вопросом — как такое возможно? Я усвоил основные знания за 2 недели, и теперь могу построить почти все?
С React все было по-другому. Временами это было очень неприятно. Но я все равно любил его просто потому, что это JavaScript.
Все в JavaScript удивительно, но это просто неправда
Веб состоит из HTML, CSS и JavaScript. Если мы хотим иметь глубокое понимание этого, мы не должны путать себя с утверждением, что все является JavaScript.
С Vue.js у меня есть ощущение, что я получаю гораздо больше общих знаний, связанных с вебом, а не только с Vue.
С React все было наоборот. Вам нужно сломать свое глубокое понимание Интернета, чтобы принять этот образ мышления.
Проблема в том, что веб останется, а React исчезнет. Это не язык программирования, а просто библиотека.
Vue работает как веб. Это набор компонентов, похожих на HTML, генерирующих события, как настоящий Интернет
Да, вы не передаете функцию в качестве входного параметра. Вы перехватываете всплывшее событие, созданное дочерним компонентом.
Так же, как и в реальной сети.
Не преувеличиваю?
Хорошо, возможно!
Тем не менее, я по-прежнему могу назвать React хорошей технологией, которая продвинула веб разработку на новый уровень. Несмотря на то, что я не согласен с тем, что веб работает только на JavaScript.
Но у меня есть ощущение, что я могу лучше изучить основы с Vue, а также я могу сосредоточиться на реальной бизнес-проблеме, а не на реализации.