Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

observable is not working when placed inside a function #3806

Open
thoriqadillah opened this issue Nov 29, 2023 · 3 comments
Open

observable is not working when placed inside a function #3806

thoriqadillah opened this issue Nov 29, 2023 · 3 comments
Labels

Comments

@thoriqadillah
Copy link

I want to make an indirection of url query state using mobx in svelte. i try to make it like this

import { action, autorun, observable } from "mobx";
import type { State, Value } from ".";

export function UrlState<T extends Value>(key: string, defaults?: T): State<T> {
    const param = new URLSearchParams(window.location.search)

    const k = key
    const initialValue = param.get(k) as T ?? defaults as T

    const url: State<T> = observable({
        value: initialValue,
        update: action((value: T) => {
            url.value = value;
        
            const urlParam = new URLSearchParams(window.location.search);
            urlParam.set(k, String(value));  // Use the argument value instead of url.value
            window.history.pushState(null, '', `?${urlParam.toString()}`);
        }),
        watch: (callback: (value: T) => void) => {
            autorun(() => callback(url.value))
        }
    })

    return url
}

import { LocalStorageState } from "./local-storage"
import { UrlState } from "./url"

export type Value = number | string | boolean
export interface State<T extends Value> {
    value: any
    update(value: T): void
    watch: (callback: (value: T) => void) => void
}

type StateProvider = 'url' | 'local-storage'

export function useState<T extends Value>(provider: StateProvider, key: string, defaults?: T): State<T> {
    if (provider === 'url') {
        return UrlState(key, defaults)
    }

    return LocalStorageState(key, defaults)
}

and call it with this

const urlState = useState<number>('url', 'counter')

i have a reactive counter on the html, and then

<p>{urlState.value}</p>
<button on:click={() => urlState.update(counter++)}>increment</button>

the problem is, the {urlState.value} is not reflecting the counter variable. but, when i change the {urlState.value} to {url.value}, the value is changed each update

Intended outcome:
the {urlState.value} will reflect the counter variable

Actual outcome:
the {urlState.value} is not reflecting the counter variable. even with as simple as this was not working either

function test() {
   const url = observable({
       value: 0,
       update: action((value: number) => {
           url.value = value;
       
           const urlParam = new URLSearchParams(window.location.search);
           urlParam.set('count', String(value));  // Use the argument value instead of url.value
           window.history.pushState(null, '', `?${urlParam.toString()}`);
       }),
       watch: (callback: (value: number) => void) => {
           autorun(() => callback(url.value))
       }
   })

   return url
}

const urlState = test()

How to reproduce the issue:
use the following function

function test() {
   const url = observable({
       value: 0,
       update: action((value: number) => {
           url.value = value;
       
           const urlParam = new URLSearchParams(window.location.search);
           urlParam.set('count', String(value));  // Use the argument value instead of url.value
           window.history.pushState(null, '', `?${urlParam.toString()}`);
       }),
       watch: (callback: (value: number) => void) => {
           autorun(() => callback(url.value))
       }
   })

   return url
}

const urlState = test()

Versions
6.12.10

@kubk
Copy link
Collaborator

kubk commented Nov 29, 2023

You need to mark your component as an observer somehow. Do you use this package https://github.com/xelaok/svelte-mobx? I believe it’s better to address it there, since the Mobx organization doesn’t maintain any Svelte integration.

@thoriqadillah
Copy link
Author

How to mark my component as observer? And no, i did not use svelte-mobx. I only use the vanilla/core mobx

I just confused that if my observable is wrapped inside a function and then return it, the reactive suddenly doesn't work. Of course i can use watch to watch if the value is changing. But the fact that the behavior is different if it's wrapped or not, feels wrong to me

@urugator
Copy link
Collaborator

If you observe any kind of reactivity in your templates, it's not provided by observable. You can probably remove the observable call and it will work the same way. Without any bindings, Svelte is completely unware of mobx's observables.
Don't use Mobx with Svelte, it doesn't make sense. Svelte solves the same problem by different means.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

3 participants