Svelte - использование Context API (setContext / getContext) при обычной передаче реквизита - PullRequest
0 голосов
/ 23 апреля 2020

Вот простой пример:

<script>
    import Button from './Button.svelte';

    let text = 'Click me!';
    let sayHello = () => alert('Hello!');
</script>

<Button {text} {sayHello}/>
<Button {text} {sayHello}/>
<Button {text} {sayHello}/>

И если я правильно понял, поскольку может быть много <Button {text} {sayHello}/>, было бы неплохо пропустить пропуски, проходящие как-то

И вот идет Контекст API :

<script>
    import Button from './Button.svelte';
    import { setContext } from 'svelte';
    import { text, sayHello } from './data.js';

    setContext(text, 'Click me!');
    setContext(sayHello, () => alert('Hello!'));
</script>

<Button/>
<Button/>
<Button/>

И где-то в ./Button.svelte есть getContext() использование, et c


Таким образом, единственная причина использовать Context API Svelte ?

- это возможность пропускать аналогичные передачи.

1 Ответ

2 голосов
/ 23 апреля 2020

Итак, единственная причина использовать контекстный API Svelte - это возможность пропускать аналогичные пропуска?

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

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

С помощью props явно указывается, какие данные нужны кнопке и откуда это. С другой стороны, в контексте вы видите только одну сторону отношений одновременно. В родительской части вы не видите, как используются данные (или даже если они вообще используются). То же самое у ребенка, вы не видите, откуда оно.

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

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

Однако существуют ситуации, когда реквизит не подходит. То есть, когда компонент потребителя данных не является прямым потомком компонента поставщика данных.

Например, в вашем приложении может быть какой-то сеанс пользователя. Скорее всего, он будет храниться в компоненте рядом с root вашего дерева компонентов (например, App), но он будет необходим в компонентах на несколько уровней вложения глубже. Например, в компоненте, отображающем имя пользователя. Или где-то еще на странице, отображая некоторые части в зависимости от того, аутентифицирован ли пользователь или нет.

Вы можете проходить мимо всех компонентов через линию, но это отчасти безумие. Это будет ie всех промежуточных компонентов данных, с которыми они абсолютно не связаны.

Таким образом, в таком случае контекст имеет смысл. Вы могли бы setContext в компоненте App и получать к нему доступ только из тех компонентов, которые в нем нуждаются.

Другим примером может быть какой-то "составной" компонент, в котором есть компонент обертки (для пример формы) и несколько компонентов, которые могут использоваться внутри нее (например, входные данные), и это зависит от некоторых настроек в контейнере.

<Form>
  <Input />
</Form>

Здесь компонент Form не может передавать реквизиты к компоненту Input, поскольку Input не создается непосредственно в компоненте Form. Он подается к нему посредством слота, и Form не может видеть содержимое этого слота.

Тем не менее, Input вложено в Form в результирующем дереве компонентов, и так что вы можете передавать данные между ними через контекст.

Подводя итог, контекст действительно предназначен для ситуаций, когда вы не можете использовать реквизит. Либо потому, что это было бы невыполнимо и привело бы к плохой архитектуре, либо потому, что это технически невозможно (слоты).

В качестве альтернативы контексту вы можете хранить данные в выделенном модуле JS, который оба поставщика и потребитель получит доступ (например, import { setData, getData } from './data-source.js'), НО, что сделает ваши компоненты одиночными. Эти данные могут быть только глобальными. С помощью контекста, с другой стороны, вы можете иметь столько «областей» изолированных данных, сколько вам нужно, по одному для каждого экземпляра компонента поставщика данных. В приведенном выше примере Form несколько компонентов <Form> могут сосуществовать в вашем приложении одновременно, каждый из которых имеет свои собственные данные в контексте. (Они могут даже быть вложены друг в друга, и это сработает.)

В заключение, вот совет. Контекст в Svelte реализован с помощью объекта JS Map, поэтому вам не нужно использовать необработанные строки в качестве ключей контекста. Я обычно использую простые объекты (или Symbol, если вы хотите быть модными), которые я экспортирую из чего-то вроде constants.js модуля. Это в значительной степени смягчает проблемы с ошибками и IDE, о которых я упоминал ранее.

constants.js

export const key = {name: 'my-context'}

Form.svelte

<script>
  import { setContext } from 'svelte'
  import { key } from './constants.js'

  setContext(key, { ... })
</script>

<slot />

Input.svelte

<script>
  import { getContext } from 'svelte'
  import { key } from './constants.js'

  const { ... } = getContext(key)
</script>

...

Это исключает любой риск столкновения контекстной клавиши с необработанной строкой. Это снова приводит к ошибочному вводу в игру с ошибкой и громкой ошибкой sh (что хорошо). И это дает вашей IDE гораздо лучшую подсказку о том, что происходит в вашем коде (импорт ES может быть легко проанализирован инструментами разработки, в то время как строки являются для них просто случайными BLOB-объектами), что делает его гораздо более полезным для вас, когда вы ' мне нужно провести рефакторинг этого ...

...