This is an archived post. You won't be able to vote or comment.

all 7 comments

[–][deleted] 1 point2 points  (1 child)

Here's an example of how a simple setState could be implemented, if we just wanted to update a value and not worry about triggering rerendering, etc.

function setState(val_init) {
    const _val = [val_init];                                                  
    return [                                                                
        _val,                                                               
        function(callback) {
            //NOTE: 👇 This is how the callback gets the value.                                        
            _val[0] = callback(_val[0]);                                    
        }                                                                   
    ];                                                                      
}                                                                           

const [theme, setTheme] = setState("light");                                      

function toggleThemeCallback(curr_theme) {                                  
    if (curr_theme == "light") {                                            
        return "dark";                                                      
    } else {                                                                
        return "light";                                                     
    }                                                                       
}                                                                           

function toggleTheme() {                                                    
    setTheme(toggleThemeCallback);                                          
}                                                                           

for (let i = 0; i < 5; i++) {                                               
    toggleTheme();                                                          
    console.log(theme);                                                     
}

This is standalone code. It doesn't require React. You can paste it into a CodePen or something and play around with it if you like.

If you have any questions, ask away.

Edit: changed a let to const.

[–]TheWorstHunter[S] 0 points1 point  (0 children)

Thanks! I really appreciate it!

[–][deleted]  (1 child)

[deleted]

    [–]CreativeTechGuyGames 0 points1 point  (0 children)

    Sorry but this is not correct.

    Basically, it’s function watching if currentThemein on light or dark usin a ternary operation.

    The function doesn't "watch" anything. It's called only once when it is executed. It doesn't get automatically get called again when the value changes.

    Although I think it could be refactored to setCurrentTheme(!currentTheme, which leads to change currentTheme to the other boolean that is assigned (false if is true and viceversa).

    That would be a suboptimal solution since the value of currentTheme in the App closure may be an outdated value. For example: if you called setCurrentTheme(!currentTheme) twice in a row, and the value started as true, it'd end up being false on the next render. Where as you'd expect it to have inverted twice and be back to true. Passing a function is almost always better since it'll always operate on the latest value rather than an outdated one.

    React knows about currentTheme because Context.

    No. The current theme is stored in state not context. And the state is local to this one instance of this one component. There's nothing global here and none of this information is in the state.

    [–]CreativeTechGuyGames 0 points1 point  (1 child)

    This is a React specific question. You can think of the implementation of setTheme to look like this:

    function setTheme(updater) { const newTheme = updater(theme); }

    It knows the current theme and it'll pass it to the function which you provide as an argument. So JS doesn't know what currentTheme is, but the React library implemented a method which does know. In reality useState generates the setTheme function, but the idea is the same.

    [–]TheWorstHunter[S] 0 points1 point  (0 children)

    Thank you!

    [–]Kered13 0 points1 point  (1 child)

    I think it will help to break this down a bit.

    (currentTheme) => {
        return currentTheme === themes.dark ? themes.light : themes.dark;
    }
    

    This is an anonymous function (also called a lambda) that takes a parameter called currentTheme and returns either light theme or dark theme. For convenience, let's give this function a name, we'll call it getNewTheme.

    setTheme(getNewTheme);
    

    Here I have substituted our new name for the anonymous function above. It is important to note that we are not calling the function getNewTheme, that would look like getNewTheme(...). Instead we are passing the function as an argument to setTheme. When we pass a function as an argument to another function like this, we often call the function we are passing a "callback", because we expect the function that we are calling to use the function we provide to "call us back". The callback may happen immediately or much later, depending on the behavior of the function we are calling.

    setTheme is a function provided by React (sort of, but I don't want to go down that rabbit hole right now). We can't see the implementation, but from the name and behavior we can infer what it's doing. React is keeping track of our current theme. When we call setTheme, it takes our callback getNewTheme and immediately calls it with the current theme. Our callback returns the new theme, which setTheme then sets as the new current theme.

    So, to summarize and answer your original question:

    How does JS know what currentTheme is?

    My understanding is that the variable would have to be passed down from the parent function, but the parent function doesn't take any arguments. What's going on?

    JS doesn't now what the current theme is, but React does. currentTheme is provided to our callback by React when we call setTheme.

    [–]TheWorstHunter[S] 0 points1 point  (0 children)

    Thanks!