Спецификация поставщика контекста SolidJS

Я следую контекстному примеру из учебника, что я понимаю из примера, это использование настроенного поставщика:

import { createSignal, createContext, useContext } from "solid-js";

const CounterContext = createContext();

export function CounterProvider(props) {
  const [count, setCount] = createSignal(props.count || 0),
    counter = [
      count,
      {
        increment() {
          setCount((c) => c + 1);
        },
        decrement() {
          setCount((c) => c - 1);
        },
      },
    ];

  return (
    <CounterContext.Provider value = {counter}>
      {props.children}
    </CounterContext.Provider>
  );
}

export function useCounter() {
  return useContext(CounterContext);
}

У меня три вопроса:

  1. Я не смог найти никакой спецификации о том, как определить поставщика пользовательского контекста, кроме приведенного выше примера. Есть ли какой-либо стандарт или спецификация, которым нужно следовать?

  2. Где в этом примере находится привязка между CounterContext и CounterProvider? Это в этой строке? <CounterContext.Provider value = {counter}>. В сочетании с createSignal затем используется в счетчике?

Таким образом, зависимость будет следующей: createSignal->counter->CounterProvider?

  1. Я не смог найти ни одного примера контекста в формате jsx о createContext с более сложными объектами, только в синтаксисе typescript. Может ли это быть действительным примером?
const SomeContext = createContext({
  someProp: "defaultString",
  someAction: function(){
    console.info('something')
  }
});
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
1
0
235
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

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

Контекст — это способ передачи значений вниз по дереву компонентов, минуя иерархию компонентов. По сути, это область JavaScript, в которой компоненты получают значения напрямую, а не вручную. Помните, что в отличие от React, компоненты Solid компилируются в функции JavaScript, а функции могут получать доступ к значениям из своих внешних областей видимости.

Context.Provider оборачивает внутренние компоненты и предоставляет значения с помощью обычной цепочки областей видимости JavaScript. useContext просматривает предоставленный контекст в своих внешних областях и получает значение, если оно есть, если нет, использует значение по умолчанию. В случае нескольких провайдеров одного и того же контекста, как и следовало ожидать, будет использоваться самый внутренний, поскольку поиск переменной идет из внутренней области через самую внешнюю.

Чтобы понять больше, вы можете прочитать контекстную документацию React, Solid заимствует идеи для контекстного API из React.

Пример выглядит сложным, потому что объект с методами, хранящимися в контексте, попробуйте более простой.

import { createContext, useContext } from 'solid-js';
import { render } from 'solid-js/web';

const CounterContex = createContext<number>(0);

const Child = () => {
  const count = useContext(CounterContex);
  return (
    <div>{count}</div>
  );
};

const App = () => {
  return (
    <div>
      <CounterContex.Provider value = {10}>
        <Child />
      </CounterContex.Provider>
    </div>
  );
}

render(App, document.querySelector('#app'));

Если вы не укажете значение, будет использоваться значение по умолчанию:

import { createContext, useContext } from "solid-js";
import { render } from "solid-js/web";

const CounterContex = createContext<number>(0);

const Child = () => {
  const count = useContext(CounterContex);
  return <div>{count}</div>;
};

const App = () => {
  return (
    <div>
      <Child />
    </div>
  );
};

render(App, document.querySelector("#app"));

Вы можете перезаписать значение контекста на разных уровнях дерева компонентов:

import { createContext, useContext } from "solid-js";
import { render } from "solid-js/web";

const CounterContex = createContext<number>(0);

const Child = () => {
  const count = useContext(CounterContex);
  return <div>{count}</div>;
};

const App = () => {
  return (
    <div>
      <CounterContex.Provider value = {10}>
        <Child />
        <CounterContex.Provider value = {20}>
          <Child />
        </CounterContex.Provider>
      </CounterContex.Provider>
    </div>
  );
};

render(App, document.querySelector("#app"));

Теперь давайте сохраним сигнал в контексте и используем внутри дочернего компонента:

import { createContext, useContext, createSignal } from "solid-js";
import { render } from "solid-js/web";

const [count, setCount] = createSignal(0);

const CounterContex = createContext({
  count,
  setCount,
});

const Child = () => {
  const { count, setCount } = useContext(CounterContex);

  return (
    <div onClick = {() => setCount(count() + 1)}>
      Click to increment: {count()}
    </div>
  );
};

const App = () => {
  return (
    <div>
      <Child />
    </div>
  );
};

render(App, document.querySelector("#app"));

Давайте рефакторим предыдущий пример. В этом случае мы будем использовать undefined в качестве значения по умолчанию, но позже перезапишем его геттером и сеттером из сигнала с использованием поставщика контекста:

import { createContext, useContext, createSignal } from "solid-js";
import { render } from "solid-js/web";

const CounterContex = createContext<any>();

const Child = () => {
  const { count, setCount } = useContext(CounterContex);
  return (
    <div onClick = {() => setCount(count() + 1)}>Click to increment: {count}</div>
  );
};

const [count, setCount] = createSignal(0);
const App = () => {
  return (
    <div>
      <CounterContex.Provider value = {{ count, setCount }}>
        <Child />
      </CounterContex.Provider>
    </div>
  );
};

render(App, document.querySelector("#app"));

Теперь пришло время реализовать пример, который вы публикуете. Ваш упакован в компонент под названием CounterProvider, но я опубликую его прямо. Вы можете переместить логику в компонент в любое время:

import { createContext, useContext, createSignal } from "solid-js";
import { render } from "solid-js/web";

const CounterContex = createContext<any>();

const Child = () => {
  const [count, { increment, decrement }] = useContext(CounterContex);
  return (
    <div>
      <div>{count()}</div>
      <div onClick = {() => increment()}>Click to Increment</div>
      <div onClick = {() => decrement()}>Click to Decrement</div>
    </div>
  );
};

const [count, setCount] = createSignal(0);

const o = [
  count,
  {
    increment() {
      setCount((c) => c + 1);
    },
    decrement() {
      setCount((c) => c - 1);
    },
  },
];

const App = () => {
  return (
    <div>
      {/* This time we use an array rather than an object as the context value */}
      <CounterContex.Provider value = {o}>
        <Child />
      </CounterContex.Provider>
    </div>
  );
};

render(App, document.querySelector("#app"));

Теперь, чтобы ответить на ваши вопросы:

  1. Вы можете прочитать документацию по Context API на https://www.solidjs.com/docs/latest#createcontext.

  2. CounterContext — это просто компонент, который обертывает компонент CounterContext.Provider, чтобы упростить его использование. Это не часть API.

  3. Как только вы поймете идею контекстного API, вы увидите, что синтаксис машинописного текста не имеет к нему никакого отношения. Typescript используется для аннотирования значения, хранящегося в контексте, для получения подсказок типа, и это все, что нужно сделать. Типы не влияют на хранимое значение.

Думаю, я понял, поэтому функция useContext вернет любое значение свойства, переданное в объявление тега Context.Provider?

Typo 20.11.2022 19:25

@Опечатка Точно. Он просматривает переданный контекст и получает значение, если оно есть, если нет, использует значение по умолчанию. Обновлено: обновлен ответ с этой информацией.

snnsnn 20.11.2022 20:38

поэтому тот факт, что вы передаете установщик и получатель из createSignal внутри массива, делает его реактивным? Я имею в виду следующее: если дочерний компонент запрашивает объект {o} без объявления его с помощью createSignal, будет ли содержимое дочернего элемента динамически обновляться только потому, что он использует поставщика контекста?

Typo 20.11.2022 23:57

Да, сигнал делает это значение контекста реактивным. При его обновлении обновляются все дочерние элементы, использующие это значение partuclar. Использование массива для удобства вызвано деструктированием.

snnsnn 21.11.2022 01:50

Другие вопросы по теме