-
Notifications
You must be signed in to change notification settings - Fork 1.2k
context -> recoil / recursive state #498
Comments
Sorry, could you explain what you are trying to accomplish? |
Sorry, I am not very good at explaining. I will try a different approach to explaining my use-case, hope it gets clearer. In a documentation-type platform, I have the following structure document(page)-story(An example)-controls(props for each example) Some types of ‘controls’ can have controls of their own (array-type control, or object-type control). In the context API, I have two context providers, based on the same context:
The first one is created in the root context state The second one is created in array/object-type controls to wrap their (recursive) children What this provides me is the ability to simply consume the context on each child control, regardless if its part of the main story object, or part of control itself. Here is a small video, showing the above at work (array-type editor that has child editors of its own for each row): |
Ok, so you have controls with either simple state or state composed of compound nested controls. Still not clear what the specific issue is? |
Thanks for looking into this @drarmstr - yes, that's correct - nested/recursive state. The specific issue is that using recoil selectors, I can not update 'different' state with the same selector. Here is my hook, that returns a control and a setter (it is used by all editors that need to edit some cotrol value): https://github.com/ccontrols/component-controls/blob/d1543b6f7b10d663d04528168c56db3c0f553ea1/core/store/src/state/recoil/controls.tsx#L45 The setter needs sometimes to update the simple state, sometimes needs to update the parent nested controls state. With context API, I have two different context providers, however, in recoil I do not see a way of nesting selectors. I am not sticking to have the exact same implementation (although it would be nice to not have to modify my code using the state setter hook too much), so even if its a different approach, do you have any example where updating recursive state with recoil? |
You may want to break up the controls state into individual atoms per control using something like |
@drarmstr - thanks, but the atomFamily is a bit out of the scope here (to subscribe for each individual control/property value). Once i get it to work for all controls on the current level i could indeed split up into family selectors. My issue and still from your response - those are different atoms/selectors. What i need is to subscribe to some state without the editors even knowing if they are editing main-level state or any of the nested states. As i mention - react context allows for multiple providers, and the editors simply consume - without ever knowing if they are consuming a main-level provider or a sub-level provider. Sorry but i still dont see in your answer how the editors can abstract from which selectors/atoms they are consuming. If you could post even some mock up code that would help - really no need to go through my code, i can even create a very simple use-case of nested state if that would help to get it going. |
I am using the term nested as it seems you preferred it, but this can be confusing. Recoil can of course deal with simple nested state - the issue is more appropriately called recursive i think - the same state that can keep being repeated in children. Sorry if any confusion come out, I dont mind calling it any which way as long as we have the same thing in mind :) |
The following is super simple and contrived, but is something like it helpful? type ControlState = {
type: 'string',
value: string,
} | {
type: 'list',
values: ReadOnlyArray<ControlID>,
};
const controlState = atomFamily<ControlState, ControlID>({
key: 'Controls',
default: {type: 'string', value: ''},
}); Then you could get and manipulate the atom for each control. either as a simple value: const setControlState = useSetRecoilState(controlState(controlID));
setControlState({type: 'string', value: "Hello World"}); or a compound value: setControlState({type: 'list', values: [firstControlID, secondControlID]}); A selector could provide derived state to abstract the results of the different types. Again a very contrived example: const abstractedControlState = selectorFamily<string, ControlID>({
key: 'AbstractedControl',
get: controlID => ({get}) => {
const control = get(controlState(controlID));
switch (control.type) {
case 'string':
return control.value;
case 'list':
return get(waitForAll(control.values.map(abstractedControlState)).join(', ');
}
},
}); |
Thanks a lot @drarmstr i will try to set up a use case sample repo and will start It with your example above - i am afraid At first look that its not what i need(hard-coding the ‘list’ type, as i need abstraction at the editors level(where the state is consumed) - some are arrays, some are objects and more editors can be created) but It will give us a common base to try to find a solution. One solution i tried today was to create dynamically new selectors and pass a selector to each editor from its parent(either from the main state or another editor being the parent). Its also convoluted but works to some extent, except unique selector names are cached. It feels i would really like to have RecoilRoot or other container to be able to change/update the behavior of existing selectors by name(ie - override selectors/atoms just for the specific conext) - this approach makes it really easy and natural to create such recursive state with context api. Thanks again, will post more Tomorrow.. |
The argument I've seen for context switching so far is mostly when you are using nested React renderers and need to bridge the nested |
Thanks @drarmstr - any other ideas for making this not hard-coded on the state side? Do you think my other attempt(create selectors on the fly and pass them from parent to child editors) can have some legs? I feel i am really close to be able to use recoil in production. Do you have a list of items to address, i would add To following and maybe we can consolidate my items:
I have a few other items that are now great, thanks to everyone involved.
|
How about create an atom in component and give it to context like: const context=createContext();
function Provider({children}){
const [state]=useState(()=>atom({...}))
return <context.provider value={state}>{childern}</context.provider>
} Now in children components: function Comp(){
const atomState= useContext(context)
....
} |
Hi,
I am trying to re-create a react context implementation now using
recoil
and want to create a recursive state implementation:In the context API, I do have two context providers over the same context - one for the outer object, and one created for each child that has recursive value as Controls.
For recoil, I am trying to accomplish something similar (with an inner RecoilRoot?) and was wondering if I could somehow change the setter/getter for a selector within the RecoilRoot context?
LMK if posting links to the recoil and context API source will help
The text was updated successfully, but these errors were encountered: