Рубрики
Без рубрики

Реквизиты по умолчанию в React / Teadercript

[Отказ от ответственности: мой опыт Dev довольно существенный, но я только начал делать Teamprctry, о … о … Теги от React, Tymdercript, JavaScript, Учебник.

[ Отказ от ответственности : Мой опыт Dev довольно существенный, но я просто Начал делать Typearctry, о … около 3 недель назад. Так что, если я что-то прикрутил в этой статье, пожалуйста, не стесняйтесь называть мою стеобразимость в комментариях.]

Я только что побежал во что-то очень … странные Отказ Это один из тех моментов программирования, которые заставляют вас остановиться и сказать: «Подождите … Это не может быть так, как это, правильно ??? ” Это связано с реализацией значений по умолчанию для компонентных реквизитов в React/Teadercript.

Настройка

Наша команда только что начала совершенно новые «зеленые поля» проекта. Это будет написано в реакции. (Здорово! Это моя специальность.) В частности, он будет использовать TeampScript И реагировать. (МММ ОК. У меня есть кто-то узнать.) Я хотел бы забрать ноги мокрыми в проекте TS на некоторое время. Так что я с нетерпением погрузился. Но в последнюю неделю – или так что-то действительно бросило меня за петлю.

Чтобы проиллюстрировать эту проблему, я собираюсь взять что-то с компонента равного OL ‘JS и преобразую его в компонент TS. Ступень моего компонента JS выглядит так:

export default function MyJSComponent(props) {
   return (
      <>
         Here is MyJSComponent:
{props.children} ); } MyComponent.propTypes = { requiredString: PropTypes.string.isRequired, requiredNumber: PropTypes.number.isRequired, optionalBoolean: PropTypes.bool, optionalString: PropTypes.string, optionalNumber: PropTypes.number, }; MyComponent.defaultProps = { optionalBoolean: true, optionalString: 'yo', optionalNumber: 42, };

Здесь ничего не хочет. Мертвый простой компонент, который принимает до 5 реквизитов, с 2 из этих реквизит. Для 3 необязательных реквизитов присваиваются значения по умолчанию. Если компонент упаковочный другой контент, этот контент будет отображаться с помощью ropps.bildren Отказ Это в основном Реагировать 101 Отказ

Итак, давайте установим об преобразовании этого в Typeyctry. В TS мы можем выводить типы данных прямо в подписи функции. А в TS, как и в JS, мы можем поставлять значения по умолчанию для дополнительных параметров – вправо в подписи функции. Так что это может выглядеть что-то подобное:

export default function MyTSComponent(
   requiredString: string,
   requiredNumber: number,
   optionalBoolean: boolean = true,
   optionalString: string = 'yo',
   optionalNumber: number = 42,
) {
   return (
      <>
         Here is MyComponent:
{props.children} ); }

Кроме … это не работает, не делает это? Это не удается на двух ключевых уровнях:

  1. При реакции вызывает компонент, он не поставляет опоры на компоненты как массив аргументов. Он снабжает их в одном объекте – реквизит объект. Таким образом, TS будет жаловаться на вышеуказанный код, потому что это поймет, что реквизит объект не коррелирует с Обязательно настроить Тип Строка Отказ

  2. Вышеуказанный код уничтожает стандартное соглашение о реагировании о возможности позвонить roppsshildren. . Мы не определили ни одного из аргументов как реквизит И поэтому нет нет ropps.bildren

Другими словами, подход выше работает отлично, когда мы пишем «регулярную» функцию TS. Но это не будет работать для TS/React Компонент Отказ Нам нужно будет учитывать тот факт, что все реквизиты передаются в компонент как единый объект.

Один подход – изменить ваш tsconfig.json отключить строгий Режим и разрешить неявное любой Типы. Это было бы выглядеть так:

export default function MyTSComponent(props) {
   return (
      <>
         Here is MyComponent:
{props.children} ); }

Со всеми вашими конфигами отключены/расслабленные, вы действительно можете получить вышеуказанный код для запуска/компиляции. Но если ваше решение проблем TS – отключить мощность TS, то … не используйте TS.

И если ваш ответ на проблемы кодирования на любом языке выключить строгий Режим или для расслабления конструкции Core Config … Ну, давайте просто скажем, что ничего в этой статье – или весь этот сайт – поможет вам любым способом.

Предполагая, что ты не В пользу отключения основных сил TS, следующий шаг – выяснить, как получить TS, чтобы «принять», что реквизит объект. Другими словами, нам нужно явно определить, что в реквизит .

Встроенный тип-намекание

Я верю, что в TS, когда это возможно, лучше, если вы можете определить ваши типы данных Прямо в подписи функции Отказ Это эффективно. Это легко для других dev к “Grok”. Так что теперь, когда мы знаем, что мы должны специально определить реквизит Объект передается, может быть, мы можем сделать это?

export default function MyTSComponent(props: {
   requiredString: string, 
   requiredNumber: number, 
   optionalBoolean: boolean = true, 
   optionalString: string = 'yo',
   optionalNumber: number = 42,
   children: JSX.Element,
}) {
   return (
      <>
         Here is MyComponent:
{props.children} ); }

Кроме … это не работает, не делает это? Если вы попробуйте набрать это в своем IDE, вы заметите, что он, по большей части, работа – до тех пор, пока вы не достигнете точки, в которой вы пытаетесь определить значения по умолчанию в дополнительных свойствах. (Кроме того, даже если значения по умолчанию работали, идея необходимости вручную определять roppshildren просто … Yuck .)

Интерфейсы

Мне кажется, что интерфейсы – это «по умолчанию», чтобы обрабатывать эти вроды. С хорошим интерфейсом вы можете окончательно вводить все значения, которые ожидаются в реактивных традиционных реквизит объект. После того, как звонил со многими разными конфигурациями, это то, что я придумал:

interface Props extends PropsWithChildren{
   requiredString: string,
   requiredNumber: number,
   optionalBoolean?: boolean,
   optionalString?: string,
   optionalNumber?: number,
}

export default function MyTSComponent({
   requiredString,
   requiredNumber,
   optionalBoolean = true,
   optionalString = 'yo',
   optionalNumber = 42,
   children,
}: Props) {
   return (
      <>
         Here is MyComponent:
{children} ); }

В отличие от других попыток, показанных выше, это на самом деле работает Отказ Реагистрация знает, какие значения необходимы, и какие из них являются необязательными. TeadingScript понимает тип, связанный с каждым аргументом. Но ИМХО, этот подход еще есть … проблемы.

  1. Полный список свойств прописан дважды – один раз в интерфейсе, а один раз в функциональной подписи. Это необходимо, потому что, если мы пренебрегаем списком, скажем, Обязательно настроить В интерфейсе, затем TS не узнает, какой тип для него назначать. И если мы пренебрегаем списком Обязательно настроить В подписи функции он просто не будет доступен в зависимости от функции.

  2. Мы должны перечислить дети в подписи функции. Долгоему времени реагирует, что просто чувствует … Неправильно Отказ Было бы похоже на то, чтобы определить console.log () Метод, прежде чем вы сможете его использовать. В реакции, дети Предполагается, что вы просто получите «бесплатно».

  3. Говоря о соглашениях по реагированию, деструктурирующие объекты уничтожит почти универсальную практику реагирования на обращение rops.foo или ropps.bildren Отказ Это может не быть большой сделки к некоторым. Но для меня это огромно. Когда я расчесываю через логику в компоненте, я определенно хочу иметь четкий показатель, что конкретная переменная была передана в компонент как опора. Как только вы разрушаете реквизиты OUT Из своего первоначального объекта вы теряете это четкое определение навеса.

defaultproops.

Вы можете думать: «Если вы хотите значения по умолчанию, почему бы вам просто использовать встроенные функциональные возможности для DefaultProops ?? ” Я, конечно, расследовал это. Это будет выглядеть так:

interface Props extends PropsWithChildren{
   requiredString: string,
   requiredNumber: number,
   optionalBoolean?: boolean,
   optionalString?: string,
   optionalNumber?: number,
}

const defaultProps: Props = {
   requiredString: '',
   requiredNumber: 0,
   optionalBoolean: true,
   optionalString: 'default',
   optionalNumber: 42,
}

const MyTSComponent: React.FC = (props) => {
   console.log(props);
   return (
      <>
         Here is MyComponent:
{props.children} ); }; MyTSComponent.defaultProps = defaultProps; export default MyTSComponent;

Там много нравится здесь. Он поддерживает традиционную реквизит соглашение. Это не требует явного определения roppsshildren. . Это делает для чистой функции подписи.

Одна вещь, которую я Не Вроде об этом подходе состоит в том, что я не мог получить его работать, если я также не определил значения по умолчанию внутри defaultproops. Для требуемых реквизитов Отказ Если я удалю Обязательно настроить и Требуется номер от defaultproops. Определение, TS жалуется на это. Тем не менее – это не на самом деле что большая сделка.

Так что это конец статьи? «Реальное» решение для реквизитов по умолчанию в Reaction/TS? Ммм … нет.

Нет раньше, я начал исследовать этот шаблон, чем я узнал, что есть большой толчок в амортизировать дефолтныеProps на функциональных компонентах.

Учитывая проблемы, которые я изложил выше, я не честно понимаю, почему кто-нибудь захочет обесценить дефолтныеProps на функциональных компонентах. Они говорят, что такие вещи, как, «значения по умолчанию уже обрабатываются в подписи функции». Ммм … Нет, они не (по крайней мере, не так, как правильно вмещают Reactive реквизит объект).

Независимо от скрученных рассуждений за этим, кажется, что это может произойти это снижение. Так с большой вздох Я переехал на поиск других решений.

Мой WTF?!?! Момент

Честно говоря, на данный момент я начал становиться довольно раздраженным. Что я пытаюсь сделать, в реакции/JS Пятиминутный урок Отказ Когда вы впервые начните делать реагирование с JavaScript javaScript, это простые минуты, чтобы понять, как вы можете установить значения по умолчанию в дополнительном выпры. И все же, в реакции/TS, это, казалось бы, простое операция требует прыжки через смешное количество обручей. Как это может быть???

Представьте, что вы путешествуете в другую страну – тот, который говорит на языке, очень похоже на вас. Пока вы там, вы говорите своему гиду, «на вашем языке, как я могу сказать« спасибо »?» И путеводитель по указывает на дюжину разных веб-страниц, которые все объясняют способы, которыми вы можете попробуйте сказать «спасибо» – без окончательного ответа. Наконец, туристический гид говорит: «Ну, в нашем варианте языка, есть действительно Нет простых способов сказать« спасибо ».

Что???

Это не так, как я пытаюсь перенести из JavaScript на Objective-C, или от JavaScript на C ++. Я просто переезжаю из React/Js, чтобы реагировать/ц. И я пытаюсь сделать то, что действительно должно быть Drop-Moad Simple Отказ И все еще… Я горю много Многие Часы пытаются решить эту самую основную проблему вопросов.

Тем не менее я толкнул дальше. Тот факт, что эта «проблема» чувствует себя смешным для меня, ничего не делает, чтобы помочь мне решить проблема.

Обработка функции

На данный момент я начал думать о «других» способах, которые я мог бы обеспечить значения по умолчанию. Так что я посмотрел на применение их внутри самой функции. Это выглядит так:

interface Props extends PropsWithChildren{
   requiredString: string,
   requiredNumber: number,
   optionalBoolean?: boolean,
   optionalString?: string,
   optionalNumber?: number,
}

export default function MyTSComponent(props: Props) {
   props.optionalBoolean = props.optionalBoolean !== undefined ? props.optionalBoolean : true;
   props.optionalString = props.optionalString !== undefined ? props.optionalString : 'yo';
   props.optionalNumber = props.optionalNumber !== undefined ? props.optionalNumber : 42;
   console.log(props);
   return (
      <>
         Here is MyComponent:
{props.children} ); }

Это не бросает какие-либо ответные ошибки TS. Тем не менее, это не будет бегать, потому что реагирование жалуется, что реквизит Объект не расширяется. Итак, чтобы обойти это, мы можем сделать глубокий клон реквизит с CloneObject () Функция, которую я изложил в одном из моих предыдущих статей.

[Да, да, я понимаю. Клонирование реквизит Просто так я могу вручную добавить значения по умолчанию чувствовать себя немного … Hack-Ish. Но я просто издаю прогрессирующую мысль здесь.]

Так что с дополнительной линией к клонированию реквизит Объект, код выглядит так:

interface Props extends PropsWithChildren{
   requiredString: string,
   requiredNumber: number,
   optionalBoolean?: boolean,
   optionalString?: string,
   optionalNumber?: number,
}

export default function MyTSComponent(props: Props) {
   props = cloneObject(props);
   props.optionalBoolean = props.optionalBoolean !== undefined ? props.optionalBoolean : true;
   props.optionalString = props.optionalString !== undefined ? props.optionalString : 'yo';
   props.optionalNumber = props.optionalNumber !== undefined ? props.optionalNumber : 42;
   console.log(props);
   return (
      <>
         Here is MyComponent:
{props.children} ); }

Этот подход … работает. Это компилирует. Сохраняет обычное реквизит Объект вместе с ropps.bildren Отказ И за один день или-два я действительно думал, что это было отвечать.

Тогда я начал заметить несколько раздражений …

В то время как вышеуказанный код действительно «работает» просто хорошо, я обнаружил, что все начало возобновить, когда я начал добавлять функции внутри функционального компонента. Рассмотрим этот пример:

interface Props extends PropsWithChildren{
   requiredString: string,
   requiredNumber: number,
   optionalBoolean?: boolean,
   optionalString?: string,
   optionalNumber?: number,
}

export default function MyTSComponent(props: Props) {
   props = cloneObject(props);
   props.optionalBoolean = props.optionalBoolean !== undefined ? props.optionalBoolean : true;
   props.optionalString = props.optionalString !== undefined ? props.optionalString : 'yo';
   props.optionalNumber = props.optionalNumber !== undefined ? props.optionalNumber : 42;
   console.log(props);

   const getLetterArrayFromOptionalString = (): Array => {
      return props.optionalString.split(''); 
   };

   return (
      <>
         Here is MyComponent:
{props.children} ); }

Я установил значение по умолчанию 'Йо' на Rupp.OptionalString Отказ И внутри GetletterarrayFromOptionalString () Я пытаюсь Сплит () эта строка в массив букв. Но TS не скомпировал это. Это жалуется, что Rupp.OptionalString Объект, возможно, неопределен – Хотя я четко определил значение по умолчанию в верхней части функции Отказ

Почему это делает это ?? Ну, TS видит функцию, связанную в точке, когда компонент установлен. И в точке, что компонент установлен, не было установлено значение значения по умолчанию для Rupp.OptionalString пока что. Неважно, что GetletterarrayFromOptionalString () никогда не будет называться до после значение по умолчанию было добавлено в Rupp.OptionalString Отказ TS не полностью Грока тот.

TS дроссели на это потому, что Сплит () Функция требует типа строка |. Regex Отказ Но Rupp.OptionalString это тип: строка |. undefined Отказ

Где это сделал |. undefined прийти из нашего Rupp.OptionalString тип? Это было динамично добавлено TS, потому что Дополнительное положение Параметр определяется как необязательно (то есть с ? прилагается к нему).

Когда вы добавите ? в свойство интерфейса, TS будет добавлять |. undefined как часть типа определения. Это может показаться хорошей вещью, но это может вызвать головные боли позже, потому что TS ожидает, что вы будете писать целую кучу кода, который терпимый на undefined Значения – Даже если вы знаете, что вы вручную устанавливаете значение для переменной, и это никогда не будет undefined Отказ

Annnnnd … Я возвращаюсь на чертежную доску.

Наконец – решение

На данный момент я думаю У меня есть рабочее решение. (Пока я не найду какого-либо другого краевого футляра, где все становится отбеженным …) Похоже, это выглядит:

//all.props.requires.ts
export type AllPropsRequired = {
   [Property in keyof Object]-?: Object[Property];
};

// my.ts.component.tsx
interface Props extends PropsWithChildren{
   requiredString: string,
   requiredNumber: number,
   optionalBoolean?: boolean,
   optionalString?: string,
   optionalNumber?: number,
}

export default function MyTSComponent(props: Props) {
   const args: AllPropsRequired = {
      ...props,
      optionalBoolean: props.optionalBoolean !== undefined ? props.optionalBoolean : true,
      optionalString: props.optionalString !== undefined ? props.optionalString : 'yo',
      optionalNumber: props.optionalNumber !== undefined ? props.optionalNumber : 42,
   };
   console.log(args);

   const getLetterArrayFromOptionalString = (): Array => {
      return args.optionalString.split('');
   };

   return (
      <>
         Here is MyComponent:
{props.children} ); }

Так что на самом деле происходит здесь?

Первое, что вы видите, это AllPropsrequireped тип. В TS это что называется частичный Отказ Я не собираюсь пройти по учебнику на этом здесь. Достаточно сказать, что AllPropsrequireped это тип, который сделает все свойства некоторых других общих интерфейса. Это будет важно через секунду …

Реквизит Интерфейс довольно «стандарт» – ничего слишком волшебного.

Внутри MyCsComponent Первое, что я делаю, создает новый объект, основанный на реквизит отбрасывать к типу AllPropsrequireped Отказ Другими словами, в args Объект, я раздум, что необязательно ? Индикатор на каждом из свойств.

Я делаю это, потому что каждое свойство также имела значение, передаваемое (если это потребуется), или это будет добавлена значение по умолчанию. Итак, Нет из свойств должно быть undefined и мы не хотим, чтобы тип недвижимости отразить, что это может быть неопределенный .

Внутри args Определение, первое, что я делаю, это распространяется ...реквизит объект. Я делаю это, поэтому я могу избежать разброса вручную из одного из необходимых свойств в объекте. Я хочу изложить только дополнительные свойства, и распространяется ... реквизит позволяет мне это сделать.

Затем для каждого из необязательных свойств я проверяю, если что-то передано. Если ничего не было передано (то есть, если свойство – undefined ), я установил значение по умолчанию.

Этот подход сохраняет мой ropps.bildren особенность – потому что я ничего не сделал, чтобы изменить/уничтожить оригинал реквизит объект. Но на протяжении всего компонента, в любое другое время, когда я хочу ссылаться реквизит Я буду использовать args объект.

Этот код компилирует, а линия:

return args.optionalString.split('');

бежит просто хорошо. Это не бросает никаких ошибок, потому что в args Объект, Дополнительное положение не имеет типа строка |. undefined Отказ Это просто имеет тип Строка Отказ

Это не должно быть это тяжело

Может быть, я что-то упускаю здесь. Может быть, на следующей неделе или два, я пойму, как было глупое всего немного путешествия. Кто-то в комментариях скажет что-то вроде: «Почему вы не просто использовали SetDefaultProps () ? ” И я буду чувствовать себя действительно глупо, чтобы сгорел несколько дни пытаясь изобретать колесо.

Но я знаю, что я не совсем один в этом. Если вы Google для таких вещей, как «TeamplectStept по умолчанию функциональные компоненты», вы найдете ряд статей и повторных вопросов переполнения стека, которые (попытка) решить эту же проблему. И все они бегают в те же ограничения. Это просто чувствует себя как … надзор мне.

И даже не заставляй меня на толкатель на амортизировать дефолтныеProps Для функциональных компонентов. Что просто чувствует Смешные мне. Или, может быть, это не – я не знаю. Это может быть просто что-то не «нажатие» прямо в моем мозге …

[ПРИМЕЧАНИЕ: Через несколько дней после этого было опубликовано, я придумал улучшенный/пересмотренный метод. Это выделено в части двух из этой серии …]

Оригинал: “https://dev.to/bytebodger/default-props-in-react-typescript-2o5o”