Ari24
Ari24

Reputation: 368

React hook re-renders component only when another parameter gets passed

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:

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

Answers (1)

paddotk
paddotk

Reputation: 1440

There are two important things you need to take into account:

  • Components in React are rendered based on the values and logic in the JSX. Since state is not used in your JSX, React does not get any trigger to re-render.
  • Be wary that javascript does not support changes on objects, so if you make 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

Related Questions