admin管理员组文章数量:1320632
I'm following this context example from the tutorial, from what I understand the example is using a customized provider:
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); }
I have three questions about this
1- I couldn't find any specification about how to define a custom context provider other than this example, is there any standard or specification to follow in the customization?
2- Where in this example is the binding between the CounterContext and the CounterProvider?
Is it in this line? <CounterContext.Provider value={counter}>
Combined with the createSignal then used in counter?
So the dependency would be: createSignal->counter->CounterProvider?
3- I couldn't find any context example in jsx format about createContext with more plex objects, only in typescript syntax. could this be a valid example?
const SomeContext = createContext({
someProp: "defaultString",
someAction: function(){
console.log('something');
}
})
I'm following this context example from the tutorial, from what I understand the example is using a customized provider:
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); }
I have three questions about this
1- I couldn't find any specification about how to define a custom context provider other than this example, is there any standard or specification to follow in the customization?
2- Where in this example is the binding between the CounterContext and the CounterProvider?
Is it in this line? <CounterContext.Provider value={counter}>
Combined with the createSignal then used in counter?
So the dependency would be: createSignal->counter->CounterProvider?
3- I couldn't find any context example in jsx format about createContext with more plex objects, only in typescript syntax. could this be a valid example?
const SomeContext = createContext({
someProp: "defaultString",
someAction: function(){
console.log('something');
}
})
Share
Improve this question
edited Dec 16, 2024 at 16:13
Typo
asked Nov 18, 2022 at 14:51
TypoTypo
1,9101 gold badge21 silver badges33 bronze badges
0
1 Answer
Reset to default 10Context is a object on the owner of the current reactive scope. It keeps the key-value pairs set by providers.
owner.context = { [id]: value };
When a ponent runs, it creates a reactive scope, hence a new owner. We will elaborate on this later on.
Context API is made up of three ponents:
createContext
creates a uniqueid
and aProvider
ponent.Provider
ponents uses the uniqueid
to set a value on the context object.useContext
returns the previously set value using the uniqueid
passed to it. If current owner does not have the id-value pair,useContext
checks owner's parent, then its grand parent, so on so forth until all ancestor owners are exhausted. If none of them has it, returns the default value.
Context is a way to pass values down the ponent tree without going through the ponent hierarchy. I used the term passing down, because people tend to explain how context works, but in reality it is the other way around: The useContext
hook climbs up the ponent tree looking for a specific context value using the provided key.
Here is how Solid's context API works:
When you create context via createContext
, you will be creating a unique id and a Provider ponent. That is it. You get an id and a ponent but you won't be setting anything yet.
Here is the actual code used in Solid:
function createContext(defaultValue) {
const id = Symbol("context");
return { id, Provider: createProvider(id), defaultValue };
}
https://www.solidjs./docs/latest#createcontext
Provider
ponent will use this id
when setting a value, which we will do next:
<Context.Provider value={someValue}></Context.Provider>
Context.Provider
ponents runs createProvider
function internally which in turn sets a value on the context object of the current owner:
Owner!.context = { [id]: props.value };
Owner.context
is an object because you can provide any number of context.
Owner is the reactive scope that owns the currently running code. Computations (effects, memos, etc.) create owners which are children of their owner, all the way up to the root owner created by createRoot or render. In this sense, ponents are also effects. When you create a ponent, you are creating an owner.
Owners are used to keep track of who creates whom, so that they will be disposed when their owner gets discarded. If you create an effect inside another effect, you will be creating an owner inside another owner. Basically it is a tree.
You can learn more about owner at:
https://www.solidjs./docs/latest/api#getowner
Now that we created context and set a value, it is time to access it. We use the useContext
hook for that purpose.
The useContext
hooks needs an id in order to look up a context value. When we pass the value that we get from the createContext
function, we will be providing that id.
export function useContext<T>(context: Context<T>): T {
let ctx;
return (ctx = lookup(Owner, context.id)) !== undefined ? ctx : context.defaultValue;
}
If you check the code, you will see it is a walker. The hook looks up its immediate owner for a value. If value is there, it will return it, if not, it will get the owner of the current owner, and look it up. So on and so forth, until there are no more owners to look up. In that case, default value is returned.
To reiterate, the useContext function is a walker that walks the tree of owners for a particular id on their context property.
That sums up how Solid's context API works.
The value you provide via Context API can be of any type. It could be static value or could be a signal like the one in your example.
The example looks plicated because an object with methods stored in the context. Lets try a simpler one.
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'));
If you do not provide a value, default value will be used:
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"));
You can overwrite the context value at different levels of the ponent tree:
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"));
Now, lets store a signal on the context and use in inside a child ponent:
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"));
Lets refactor the previous example. In this one, we will use undefined
as the default value but overwrite it later with a getter and setter from a signal using a context provider:
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"));
Now it is time to implement the example you post. Yours is wrapped in a ponent called CounterProvider
but I will post it plainly. You can move the logic into a ponent any time:
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"));
Disclaimer: Parts of this answer are based on content from my book, SolidJS: The Complete Guide — A prehensive guide to reactive web development with SolidJS and TypeScript. For an in-depth exploration of SolidJS, check out the book here: https://solid.courses/p/solidjs-the-plete-guide/
本文标签: javascriptContext Provider SpecificationStack Overflow
版权声明:本文标题:javascript - Context Provider Specification - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1742073702a2419280.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论