Reputation: 368
I created my own react component called useSetting
to be a wrapper around the dexie.js library (better for my use-case to use an own hook) for the indexed db. This one goes as the following:
export const useSetting = (id: string, key: string, trigger_function?: Function): [any, Function] => {
const [state, setState] = useState();
const changeStatus = (value: any) => widgetsDb.setSetting(id, key, value);
useEvent(`widget.${id}.${key}`, HashCode.value(id + key + String(trigger_function)), null, (data: any) => {
const value = (trigger_function || (() => {}))(data) || data;
setState(value);
})
useEffect(() => {
widgetsDb.getSetting(id, key).then((data: any) => {
const value = (trigger_function || (() => {}))(data) || data;
setState(value);
})
}, [id, key, trigger_function])
return [state, changeStatus];
}
and the problem is that the hook does not re-render the component if the value changed and no trigger_function was passed. To better explain this scenario see this code snippet:
const [ position, setPosition ] = useSetting(props.id, "position");
here, useSetting does not re-render the component whenever the state in the useSetting
hook changes. But when I pass a function to the trigger_function
field:
const [ position, setPosition ] = useSetting(props.id, "position", () => {});
suddenly, the component starts to rerender when the state changes. That's what really confuses me.
To give more context:
widgetsDb.getSetting
does set the initial value in useEffectuseEvent
does indeed execute the arrow function no matter if I pass trigger_function or notstate
always gets updated in the useSetting
hook whenever the arrow function in useEvent
gets executeduseEvent
is rendered from a list meaning that I have a list of components being rendered. Those are then passed into another component:App.tsx:
<div className="App">
<Background>
{componentsList.map((component: Component) => {
if (component.element === null) {
return null;
}
return <component.element id={component.fullId} key={component.fullId} />;
})}
<SettingsComponent />
</Background>
</div>
Background.tsx:
<div>
{props.children.map(child => React.cloneElement(child, {blur}))}
</div>
I have been working on this problem now for a long time and couldn't figure out anything. Unfortunately, even "similar" cases on SO or elsewhere didn't help me any further. Hope that anyone can help me out here or point me in the right direction. I'll be happy to provide more information if needed.
Upvotes: 0
Views: 1284
Reputation: 1440
There are two important things you need to take into account:
state
is not used in your JSX, React does not get any trigger to re-render.state
to be an object, React won't know if a property within it changes. This is different when using React's own setState
(in class-based components), but I don't think it'll work if you simulate that in a React hook.Upvotes: 1