S
SolidJS12mo ago
Basil

Nested Immer "produce" signals with components

I'm trying to implement something like this, which would allow me to create "nested" signals that update the upmost signal:
function createImmerSignal<T>(value: T) {
const [get, set] = createSignal(value);

function newSet(callback: (draft: Draft<T>) => void) {
const newVal = produce(get(), callback, (redo, undo) => {
// Undo and redo logic
});
// eslint-disable-next-line @typescript-eslint/ban-types
set(newVal as Exclude<T, Function>);
}

return [get, newSet];
}

type Company = {
name: string;
developers: {
name: string;
someOtherProp: string;
}[];
};

function CompOne(prop: { origCompany: Company }) {
const [company, setCompany, createNested] = createImmerSignal<Company>(origCompany);

// I'm not sure what a good syntax for this would be, or how to even get this functional. This syntax is what I've come up with:
const dev = createNested(company => company.developers[0]);

return <>
<CompTwo dev={dev} />
</>
}

function CompTwo(props) {
// createNested can be used indefinitely
const [dev, setDev, createNested] = props.dev;

setDev(draft => {
// This would update company.developers[0].someProp
draft.name = 'aaaa';
});

return <></>;
}
function createImmerSignal<T>(value: T) {
const [get, set] = createSignal(value);

function newSet(callback: (draft: Draft<T>) => void) {
const newVal = produce(get(), callback, (redo, undo) => {
// Undo and redo logic
});
// eslint-disable-next-line @typescript-eslint/ban-types
set(newVal as Exclude<T, Function>);
}

return [get, newSet];
}

type Company = {
name: string;
developers: {
name: string;
someOtherProp: string;
}[];
};

function CompOne(prop: { origCompany: Company }) {
const [company, setCompany, createNested] = createImmerSignal<Company>(origCompany);

// I'm not sure what a good syntax for this would be, or how to even get this functional. This syntax is what I've come up with:
const dev = createNested(company => company.developers[0]);

return <>
<CompTwo dev={dev} />
</>
}

function CompTwo(props) {
// createNested can be used indefinitely
const [dev, setDev, createNested] = props.dev;

setDev(draft => {
// This would update company.developers[0].someProp
draft.name = 'aaaa';
});

return <></>;
}
I'm specifically trying to avoid having to use setCompany in a nested component, because that would become pretty unwieldy very quickly:
setCompany(draft => {
draft.developers[0].someProp.anotherProp[2].enabled = true;
});
setCompany(draft => {
draft.developers[0].someProp.anotherProp[2].enabled = true;
});
However, I'm not sure how to do this.
2 Replies
lxsmnsyc
lxsmnsyc12mo ago
This seemed like createStore with produce, at first glance
Basil
BasilOP12mo ago
I'm using Immer (and its produce function) to generate patches and so I can deal with reactivity on classes/nested classes. Or, what do you mean by that? Would you even be able to use stores with Immer? Since Immer returns a completely new object, using the store setter to set the object would mean you won't get the fine-grained reactivity, right? If you mean something like:
const [store, setStore] = createStore(someDeeplyNestedObject);

setStore('some', 'path', produce(draft => {
draft.val = true;
});
const [store, setStore] = createStore(someDeeplyNestedObject);

setStore('some', 'path', produce(draft => {
draft.val = true;
});
I don't think that would work with the patch generation, since it would just make the patches relative to .some.path and you couldn't just put that into a undo/redo context. Is it even possible to do this reactively?
Want results from more Discord servers?
Add your server