Views
Show Data and Collect Input
Views serve as the presentation layer in StateWalker applications, transforming data from reactive models into user interfaces while capturing user interactions to drive application state changes. Views operate within the framework’s unidirectional data flow architecture, where they reflect output model changes on screen and update input models based on user interactions.
Views access models through the process context using the adapter pattern. This approach maintains loose coupling while enabling reactive connections between the presentation layer and application data. The process context serves as the primary mechanism for views to obtain references to both input and output models.
Views establish reactive subscriptions to output models through onChange
listeners, enabling them to respond automatically to data changes by re-rendering the interface. When output models change, views update the DOM elements to reflect the new state, ensuring the interface stays synchronized with application data.
Views capture user interactions through DOM event listeners and translate these interactions into input model updates. Form submissions, button clicks, and input changes are converted into model property updates, allowing user actions to flow into the application’s reactive system.
Views return cleanup functions to ensure proper resource management during state transitions. These cleanup functions remove DOM event listeners, unsubscribe from model change notifications, and clean up any allocated resources, preventing memory leaks and maintaining system stability.
Dual-Model Pattern: Input and Output Separation
Views follow a dual-model pattern that separates user input collection from data presentation within the unidirectional data flow architecture. Input models capture user interactions such as form field values, selection states, and focus indicators. Output models hold processed data ready for presentation including search results, error states, and loading indicators.
This separation creates a flow where user actions update input models, which controllers observe to perform business logic, eventually updating output models that views reflect back to the user. The reactive nature ensures that all UI updates happen automatically without manual intervention.
Implementation Examples
Basic View: Model Access and Reactive Rendering
This example demonstrates direct DOM manipulation for simplicity, though views can integrate with any frontend framework like React, Vue, or Svelte using their respective reactive patterns.
async function UserProfileView(context: ProcessContext) {
// Context access: Get model through process context
const userModel = getUserModel(context);
const container = document.getElementById('user-profile');
// Reactive rendering: Respond to model changes
// In React/Vue/Svelte, this would use framework-specific reactivity (useEffect, computed, $:)
const render = () => {
const user = userModel.getUser();
// Direct DOM manipulation shown here - frameworks would use their templating systems
container.innerHTML = `
<h2>Welcome, ${user.name}</h2>
<p>Email: ${user.email}</p>
`;
};
// Model subscription: Listen to changes
// Framework-specific views would integrate this with their reactive systems
const cleanup = userModel.onChange(render);
// Initial render on view activation
render();
// Cleanup function: Release subscriptions
return cleanup;
}
Interactive View: Dual-Model Pattern with User Input
This example shows vanilla JavaScript event handling and DOM manipulation. Framework-specific implementations would use their event handling systems and reactive templates while maintaining the same dual-model pattern.
async function SearchView(context: ProcessContext) {
// Registry pattern: Manage multiple cleanup functions
const [register, cleanup] = newRegistry();
// Context access: Get input and output models
const searchForm = getSearchFormModel(context); // Input model
const searchResults = getSearchResultsModel(context); // Output model
// DOM element access - frameworks would use refs, template variables, or component bindings
const formElement = document.querySelector("#search-form");
const resultsElement = document.querySelector("#search-results");
// Reactive rendering: Listen to output model changes
// Framework views would integrate this with their reactive rendering (useState, ref, reactive)
const renderResults = () => {
if (searchResults.loading) {
// Direct DOM updates shown - frameworks use declarative templates
resultsElement.innerHTML = "Searching...";
} else if (searchResults.error) {
resultsElement.innerHTML = `Error: ${searchResults.error.message}`;
} else {
resultsElement.innerHTML = searchResults.items.map(item =>
`<div>${item.title}</div>`
).join('');
}
};
register(searchResults.onChange(renderResults));
renderResults(); // Initial render
// User input handling: Update input model from DOM events
// Framework-specific views would use their event binding systems (onClick, @click, on:click)
const handleFormSubmit = (event) => {
event.preventDefault();
const query = formElement.querySelector('input').value;
// Input model update: Capture user interaction
// This pattern remains consistent across frameworks - update input models
searchForm.query = query;
searchForm.submit(); // Triggers controller logic
};
// DOM event binding and cleanup registration
// Frameworks handle event binding through their templating systems
formElement.addEventListener('submit', handleFormSubmit);
register(() => formElement.removeEventListener('submit', handleFormSubmit));
// Cleanup function: Registry releases all resources
return cleanup;
}
Framework Integration Notes
React Integration: Views would use useEffect
to subscribe to model changes and useState
to trigger re-renders. User input would be captured through JSX event handlers that update input models.
Vue Integration: Views would use watch
or computed
properties to react to model changes, with template directives handling user input and updating input models.
Svelte Integration: Views would use reactive statements ($:
) to respond to model changes and bind user input through directive syntax, maintaining the same model update patterns.
The core principle remains consistent: views subscribe to output model changes using framework-specific reactivity and update input models through framework-specific event handling, while the underlying model interaction patterns stay the same.
Key Concepts in Practice
Reactive Rendering: Views observe output model changes through onChange
subscriptions and respond by updating the DOM within the unidirectional data flow architecture. This eliminates manual DOM synchronization.
Context Access: The process context provides access to models using the adapter pattern. This maintains loose coupling while enabling views to access both input and output models.
User Input Capture: Views translate DOM events into input model updates, allowing user interactions to flow into the application’s reactive system and trigger business logic in controllers.
Resource Management: Views return cleanup functions that remove DOM event listeners and unsubscribe from model notifications. The registry pattern manages multiple cleanup operations automatically.
These patterns combine to create views that respond to model changes, capture user input, access shared resources through context, and maintain clean resource management throughout the application lifecycle.