DEV Community

tengxgfyrz67s
tengxgfyrz67s

Posted on

Browser-Storage-and-Navigation

Browser Storage and Navigation in euv

Project Code:https://github.com/euv-dev/euv

When building web applications, two common requirements are persistent data storage and URL-based navigation. euv provides direct access to browser APIs through its window() function, allowing you to interact with localStorage, sessionStorage, and the browser's Location object. This article covers how to use these APIs effectively within the euv framework, including reading and writing storage, manipulating the URL hash, and building navigation patterns.

Accessing the Browser Window

All browser API access in euv starts with the window() function, which returns a Window handle. From this handle, you can access the document, location, and various storage mechanisms:

let win: Window = window().expect("no global window exists");
let doc: Document = win.document().expect("should have a document");
Enter fullscreen mode Exit fullscreen mode

The window() function returns an Option<Window>, so you should always handle the case where it might be None (for example, when running in a non-browser environment like server-side rendering). In practice, for WASM applications running in the browser, this will always succeed.

Once you have the Window handle, you can access the Document for DOM manipulation and the Location for navigation.

Working with localStorage

localStorage provides persistent key-value storage that survives browser restarts. euv exposes this through the local_storage() method on Window:

let storage: Option<Storage> = win.local_storage().unwrap_or_default();
if let Some(storage) = storage {
    let _ = storage.set_item("key", "value");
    let value: Option<String> = storage.get_item("key").unwrap_or_default();
}
Enter fullscreen mode Exit fullscreen mode

Let's break down what's happening:

  1. win.local_storage() returns an Option<Storage>. If the browser supports localStorage (which all modern browsers do), this returns Some(storage).
  2. set_item("key", "value") writes a value to storage. It returns a Result, which you can handle with let _ = if you want to ignore errors.
  3. get_item("key") reads a value from storage, returning Option<String>. The .unwrap_or_default() converts None (key not found) to an empty string.

Storing Complex Data

Since localStorage only stores strings, you'll need to serialize and deserialize complex data. euv's JavaScript interop capabilities make it possible to work with JSON:

let storage: Option<Storage> = win.local_storage().unwrap_or_default();
if let Some(storage) = storage {
    let _ = storage.set_item("user_name", "Alice");
    let name: Option<String> = storage.get_item("user_name").unwrap_or_default();
}
Enter fullscreen mode Exit fullscreen mode

For more complex scenarios, you can use spawn_local with JsFuture to work with JavaScript's JSON.stringify and JSON.parse for serialization.

Practical Example: Persisting User Preferences

A common use case is persisting user preferences across sessions:

let win: Window = window().expect("no global window exists");
let storage: Option<Storage> = win.local_storage().unwrap_or_default();
if let Some(storage) = storage {
    let _ = storage.set_item("theme", "dark");
    let theme: String = storage.get_item("theme").unwrap_or_default();
}
Enter fullscreen mode Exit fullscreen mode

You could combine this with watch! to automatically save preferences whenever a reactive signal changes, ensuring the stored state is always up to date.

Working with the Location Object

The Location object provides access to the current URL and methods for navigation:

let location: Location = win.location();
let hash: String = location.hash().unwrap_or_default();
let _ = location.set_hash("#/about");
Enter fullscreen mode Exit fullscreen mode

Reading the Current Hash

location.hash() returns the current URL hash (the part after #), which is commonly used for client-side routing in single-page applications:

let location: Location = win.location();
let hash: String = location.hash().unwrap_or_default();
Enter fullscreen mode Exit fullscreen mode

You can use this hash value to determine which view or component should be displayed, enabling client-side routing without page reloads.

Setting the Hash for Navigation

location.set_hash() changes the URL hash, which triggers the browser's hash change event:

let _ = location.set_hash("#/about");
Enter fullscreen mode Exit fullscreen mode

This updates the URL to include #/about without reloading the page. Combined with Conditional-Rendering-and-Patterns, you can build a complete client-side router:

let location: Location = win.location();
let hash: String = location.hash().unwrap_or_default();
// Use the hash to determine which page to render
Enter fullscreen mode Exit fullscreen mode

Building Hash-Based Routing

By combining location.hash() with reactive signals and watch!, you can build a simple but effective routing system:

let location: Location = win.location();
let hash: String = location.hash().unwrap_or_default();
watch!(hash, |h| {
    // React to hash changes and update the displayed page
});
Enter fullscreen mode Exit fullscreen mode

Combining Storage and Navigation

Storage and navigation often work together. For example, you might want to save the current page state to storage so that when a user returns to your application, they're taken to the same page:

let win: Window = window().expect("no global window exists");
let location: Location = win.location();
let hash: String = location.hash().unwrap_or_default();

let storage: Option<Storage> = win.local_storage().unwrap_or_default();
if let Some(storage) = storage {
    let _ = storage.set_item("last_page", &hash);
    let last_page: String = storage.get_item("last_page").unwrap_or_default();
}
Enter fullscreen mode Exit fullscreen mode

This pattern provides a better user experience by restoring their previous state.

Using the Document Object

Beyond storage and location, the Document object gives you access to the full DOM:

let win: Window = window().expect("no global window exists");
let doc: Document = win.document().expect("should have a document");
Enter fullscreen mode Exit fullscreen mode

You can use the Document to create elements, query selectors, and perform other DOM operations as needed.

Error Handling Considerations

Browser APIs can fail for various reasons — storage might be full, the browser might restrict access, or the environment might not support certain features. Always handle Option and Result types appropriately:

let storage: Option<Storage> = win.local_storage().unwrap_or_default();
if let Some(storage) = storage {
    let _ = storage.set_item("key", "value");
    let value: Option<String> = storage.get_item("key").unwrap_or_default();
}
Enter fullscreen mode Exit fullscreen mode

Using if let Some(...) for storage and .unwrap_or_default() for individual values ensures your application degrades gracefully when browser APIs are unavailable.

Conclusion

euv provides straightforward access to browser storage and navigation APIs through the window() function and its associated objects. By leveraging localStorage for persistent data, Location for URL-based navigation, and Document for DOM access, you can build fully-featured web applications that persist user data and support client-side routing. These APIs integrate naturally with euv's reactive system — you can use watch! to respond to hash changes, store reactive signal values to localStorage, and create rich, state-aware navigation experiences.


Project Code:https://github.com/euv-dev/euv

Top comments (0)