0
votes

There are 3 files below: Toggle.jsx, PersistentState.jsx, and Particles.jsx

A site that I am building has a theme toggle. When that toggle is pressed, the page switches between dark mode and light mode. I use a custom hook (PersistentState.jsx) to store state so that the theme of the page persists through page reloads (useState() does not persist so that is why I use a custom hook).

This is how I setup usePersistentState:

const [isDark, setIsDark] = usePersistentState('theme', true);

isDark is changed depending on if the toggle is checked or not. setIsDark is changed in the toggle's onChange event.

I am trying to access the value isDark in a different file, Particles.jsx. I am unsure of how to gain access to it since I cant just import it. This is what I need help with.


Files

Toggle.jsx

import React, { Component, useEffect } from "react";
import { usePersistentState } from './../hooks';

const Theme = () => {
    const [isDark, setIsDark] = usePersistentState('theme', true); // default to dark mode

    useEffect(() => {
        isDark ? document.documentElement.classList.add('other') : document.documentElement.classList.remove('other')
    });

    return (
        <div>
            <main>
                <input id="toggle" name="toggle" type="checkbox" checked={isDark} onChange={event => setIsDark(event.target.checked)} />
                <label htmlFor="toggle" className="switch" id="switch"></label>
            </main>
        </div>
    )
}

class Toggle extends Component {
    render() {
        return (
            <Theme />
        );
    }
}

export default Toggle;

PersistentState.jsx

import React from 'react';

export default function usePersistentState(key, defaultValue) {
    const [state, setState] = React.useState(() => {
        const persistentState = localStorage.getItem(key);
        return persistentState ? JSON.parse(persistentState) : defaultValue;
    });
    React.useEffect(() => {
        window.localStorage.setItem(key, JSON.stringify(state));
    }, [state, key]);
    return [state, setState];
}

Particles.jsx

import React, { Component, useState } from 'react';
import { Particles as ReactParticles } from 'react-particles-js';

const PARAMS = () => {
    const [isdark, setIsDark] = useState(0) <- this does not work, how should I go about retrieving the value of isDark from Toggle.jsx
    console.log(isdark, setIsDark)

    return ({
        "particles": {
            "number": {
                "value": 60,
            },
            "color": {
                "value": `${isDark ? : ...}` <- where I need to use the value of isDark 
            },
            ...
}

class Particles extends Component {
    render() {
        return (
            <div className="particles">
                <ReactParticles width='100vw' height="100vh" params={PARAMS()} />
            </div>
        )
    }
}

export default Particles;
1

1 Answers

0
votes

Because your hook is not a singleton, whenever you call the custom hook the state does not persist - meaning you get new values every time.

Therefore you need to make your hook a singleton. The easiest way is to use a library like reusable and call it a day.

But if you think about it, you can make a singleton with a Context API:

// Wrap your application components
<ThemeContext.Provider value={{ isDark, setIsDark }}>...</ThemeContext.Provider>

// Change the hook implementation to use context
export default function usePersistentState(key, defaultValue) {
    const {isDark, setDark} = useContext(ThemeContext);

    React.useEffect(() => {
        ...
    }, [...]);
    return [isDark, setDark];
}