Skip to content

Commit eec6620

Browse files
committed
feat(cookbook-react-state): add comprehensive state management cookbook with useAppState examples and documentation
1 parent fe7e1bc commit eec6620

11 files changed

Lines changed: 693 additions & 0 deletions

File tree

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
---
2+
"@equinor/fusion-framework-cookbook-app-react-state": major
3+
---
4+
5+
**@equinor/fusion-framework-cookbook-app-react-state:**
6+
7+
🎉 Added new cookbook demonstrating state management with useAppState hook in React applications!
8+
9+
This comprehensive cookbook 📚 provides developers with practical examples and best practices for using the Fusion Framework state module in React applications.
10+
11+
The cookbook includes complete state management examples demonstrating simple state management, sharing state between components, and complex object state updates. It features interactive components including `UserProfileControls` and `UserProfileDisplay` components showing real-world state management patterns.
12+
13+
Key features include:
14+
- 📖 Educational documentation with learning objectives, setup instructions, and key concepts
15+
- 🔷 Full TypeScript implementation with proper type definitions
16+
- ⚡ Complete development setup with dev server and build configuration
17+
18+
Developers will learn how to configure the state module using `enableAppState`, use the `useAppState` hook for persistent state management, share state between components with unique state keys, manage complex object state with proper update patterns, and follow best practices for organizing state in Fusion applications.
19+
20+
🚀 Developers can run this cookbook to learn state management patterns:
21+
22+
```bash
23+
cd cookbooks/app-react-state
24+
pnpm install
25+
pnpm dev
26+
```
27+
28+
This cookbook serves as a complete reference implementation 🛠️ for teams adopting the Fusion Framework state module in their React applications.
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
# Fusion Framework State Module Cookbook
2+
3+
A comprehensive cookbook demonstrating how to use the Fusion Framework state module with `useAppState` hook for managing application state in React apps.
4+
5+
## 🎯 Learning Objectives
6+
7+
After working through this cookbook, you will understand:
8+
9+
- How to configure the state module in your Fusion app
10+
- How to use the `useAppState` hook for simple state management
11+
- How to share state between components with different state keys
12+
- How to manage complex object state with proper update patterns
13+
- Best practices for organizing state in Fusion applications
14+
15+
## 🏗️ Setup
16+
17+
### Prerequisites
18+
19+
- Node.js 18+
20+
- pnpm package manager
21+
- Basic knowledge of React hooks
22+
23+
### Running the Example
24+
25+
```bash
26+
# Install dependencies
27+
pnpm install
28+
29+
# Start development server
30+
pnpm dev
31+
```
32+
33+
## 📚 Key Concepts
34+
35+
### State Module Configuration
36+
37+
The state module must be enabled in your app configuration:
38+
39+
```typescript
40+
import { enableAppState } from '@equinor/fusion-framework-react-app/state';
41+
42+
export const configure: AppModuleInitiator = (appConfigurator) => {
43+
enableAppState(appConfigurator);
44+
};
45+
```
46+
47+
### useAppState Hook
48+
49+
The `useAppState` hook works similar to React's `useState` but provides persistent state across components using a unique key:
50+
51+
```typescript
52+
const [value, setValue] = useAppState<T>(key, options);
53+
```
54+
55+
**Parameters:**
56+
- `key`: Unique string identifier for the state (e.g., 'user.profile', 'app.settings')
57+
- `options`: Configuration object with optional `defaultValue`
58+
59+
**Returns:**
60+
- `value`: Current state value
61+
- `setValue`: Function to update the state
62+
63+
### State Keys Organization
64+
65+
Use hierarchical naming for better organization:
66+
- `app.*` - Application-level settings
67+
- `user.*` - User-specific data
68+
- `feature.*` - Feature-specific state
69+
70+
## 📖 Examples in This Cookbook
71+
72+
### 1. Simple State Examples (SimpleStateExamples.tsx)
73+
- **Boolean state** - notifications enabled/disabled
74+
- **String state** - language selection with type safety
75+
- **Optional state** - last login time (can be undefined)
76+
77+
### 2. Shared State Between Components
78+
- **Complex object state** - user profile (UserProfile type)
79+
- **Read-only component** - UserProfileDisplay.tsx
80+
- **Control component** - UserProfileControls.tsx
81+
82+
### 3. State Update Patterns
83+
- **Direct value updates** - simple assignments
84+
- **Functional updates** - for complex objects
85+
- **Clearing/resetting state** - setting to undefined or defaults
86+
87+
## 🔍 Code Structure
88+
89+
```
90+
src/
91+
├── App.tsx # Main app container and navigation
92+
├── SimpleStateExamples.tsx # Basic state management examples
93+
├── UserProfileDisplay.tsx # Read-only shared state component
94+
├── UserProfileControls.tsx # Interactive shared state component
95+
├── types.ts # Shared TypeScript types
96+
├── config.ts # App configuration with state module
97+
└── index.ts # App entry point
98+
```
99+
100+
## 💡 Best Practices
101+
102+
1. **Use descriptive state keys** - Choose keys that clearly describe the data
103+
2. **Define default values** - Always provide sensible defaults for better UX
104+
3. **Type your state** - Use TypeScript generics for type safety
105+
4. **Functional updates** - Use functional updates for complex state changes
106+
5. **Component separation** - Separate read and write concerns when appropriate
107+
108+
## 🔗 Related Documentation
109+
110+
- [Fusion Framework State Module](../../../packages/modules/state/)
111+
- [React App State Hook](../../../packages/react/app/src/state/)
112+
- [Fusion Framework React App](../../../packages/react/app/)
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
{
2+
"name": "@equinor/fusion-framework-cookbook-app-react-state",
3+
"version": "0.0.0",
4+
"description": "A comprehensive cookbook demonstrating how to use the Fusion Framework state module with useAppState hook for managing application state in React apps.",
5+
"private": true,
6+
"type": "module",
7+
"main": "src/index.ts",
8+
"scripts": {
9+
"dev": "fusion-framework-cli app dev",
10+
"build": "fusion-framework-cli app build",
11+
"build:pack": "fusion-framework-cli app pack",
12+
"docker": "cd .. && sh docker-script.sh app-react"
13+
},
14+
"author": "",
15+
"license": "ISC",
16+
"dependencies": {
17+
"@equinor/eds-core-react": "^0.45.0",
18+
"@equinor/fusion-framework-cli": "workspace:^",
19+
"@equinor/fusion-framework-module-state": "workspace:^",
20+
"@equinor/fusion-framework-react-app": "workspace:^",
21+
"@equinor/fusion-observable": "workspace:^",
22+
"@types/react": "^18.2.50",
23+
"@types/react-dom": "^18.2.7",
24+
"react": "^18.2.0",
25+
"react-dom": "^18.2.0",
26+
"typescript": "^5.8.2"
27+
}
28+
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import { UserProfileControls } from './UserProfileControls';
2+
import { UserProfileDisplay } from './UserProfileDisplay';
3+
import { SimpleStateExamples } from './SimpleStateExamples';
4+
5+
/**
6+
* Main App component demonstrating useAppState patterns
7+
*
8+
* This component serves as the main container for the cookbook,
9+
* showcasing both simple and advanced state management patterns.
10+
*/
11+
export const App = () => {
12+
return (
13+
<div style={{ maxWidth: '800px', margin: '0 auto', padding: '20px' }}>
14+
<h1>🔄 Fusion State Module Cookbook</h1>
15+
<p>
16+
Learn how to use <code>useAppState</code> for managing application state in Fusion Framework
17+
apps.
18+
</p>
19+
20+
{/* SECTION 1: Basic State Examples */}
21+
<SimpleStateExamples />
22+
23+
{/* SECTION 2: Shared Object State */}
24+
<section>
25+
<h2>🔗 Shared Object State</h2>
26+
<p>
27+
The components below demonstrate sharing complex object state using the same state key:{' '}
28+
<code>'userProfile'</code>
29+
</p>
30+
<p>
31+
<strong>Key Learning:</strong> Multiple components can access and modify the same state
32+
using the same key.
33+
</p>
34+
35+
{/* Display component shows current state */}
36+
<UserProfileDisplay />
37+
38+
{/* Controls component allows state modification */}
39+
<UserProfileControls />
40+
</section>
41+
</div>
42+
);
43+
};
44+
45+
export default App;
Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
import { Button } from '@equinor/eds-core-react';
2+
import { useAppState } from '@equinor/fusion-framework-react-app/state';
3+
import type { Language } from './types';
4+
5+
/**
6+
* SimpleStateExamples - Component demonstrating basic useAppState patterns
7+
*
8+
* This component showcases three fundamental patterns:
9+
* 1. Boolean state management
10+
* 2. String state with type safety
11+
* 3. Optional state (can be undefined)
12+
*
13+
* Key Learning Points:
14+
* - How to use useAppState with different data types
15+
* - Providing default values for better UX
16+
* - Hierarchical state key naming conventions
17+
* - Simple state update patterns
18+
*/
19+
export const SimpleStateExamples = () => {
20+
// EXAMPLE 1: Boolean state management
21+
// State key: 'app.notifications.enabled' - hierarchical naming for app settings
22+
const [isNotificationEnabled, setIsNotificationEnabled] = useAppState<boolean>(
23+
'app.notifications.enabled',
24+
{ defaultValue: true }, // Always provide sensible defaults
25+
);
26+
27+
// EXAMPLE 2: String state with type safety
28+
// Using custom Language type for better type safety
29+
const [currentLanguage, setCurrentLanguage] = useAppState<Language>('app.language', {
30+
defaultValue: 'en',
31+
});
32+
33+
// EXAMPLE 3: Optional state (can be undefined)
34+
// No default value means it starts as undefined
35+
const [lastLoginTime, setLastLoginTime] = useAppState<string>('user.lastLogin');
36+
37+
// Example of simple state update - setting current timestamp as string
38+
const handleLogin = () => {
39+
setLastLoginTime(new Date().toLocaleString());
40+
};
41+
42+
return (
43+
<section style={{ marginBottom: '40px' }}>
44+
<h2>📚 Basic State Management</h2>
45+
<div style={{ border: '2px solid #e0e0e0', borderRadius: '8px', padding: '20px' }}>
46+
{/* Boolean State Example */}
47+
<div style={{ marginBottom: '24px' }}>
48+
<h3>Boolean State: Notifications</h3>
49+
<p>
50+
<strong>Current Value:</strong> {isNotificationEnabled ? '✅ Enabled' : '❌ Disabled'}
51+
</p>
52+
<p>
53+
<strong>State Key:</strong> <code>'app.notifications.enabled'</code>
54+
</p>
55+
<div style={{ marginTop: '12px', display: 'flex', gap: '8px' }}>
56+
<Button
57+
onClick={() => setIsNotificationEnabled(true)}
58+
variant={isNotificationEnabled ? 'contained' : 'outlined'}
59+
>
60+
Enable
61+
</Button>
62+
<Button
63+
onClick={() => setIsNotificationEnabled(false)}
64+
variant={!isNotificationEnabled ? 'contained' : 'outlined'}
65+
>
66+
Disable
67+
</Button>
68+
</div>
69+
</div>
70+
71+
{/* String State Example */}
72+
<div style={{ marginBottom: '24px' }}>
73+
<h3>String State: Language Selection</h3>
74+
<p>
75+
<strong>Current Value:</strong> {currentLanguage}
76+
</p>
77+
<p>
78+
<strong>State Key:</strong> <code>'app.language'</code>
79+
</p>
80+
<div style={{ marginTop: '12px', display: 'flex', gap: '8px', flexWrap: 'wrap' }}>
81+
<Button
82+
onClick={() => setCurrentLanguage('en')}
83+
variant={currentLanguage === 'en' ? 'contained' : 'outlined'}
84+
size="small"
85+
>
86+
English
87+
</Button>
88+
<Button
89+
onClick={() => setCurrentLanguage('no')}
90+
variant={currentLanguage === 'no' ? 'contained' : 'outlined'}
91+
size="small"
92+
>
93+
Norsk
94+
</Button>
95+
<Button
96+
onClick={() => setCurrentLanguage('es')}
97+
variant={currentLanguage === 'es' ? 'contained' : 'outlined'}
98+
size="small"
99+
>
100+
Español
101+
</Button>
102+
</div>
103+
</div>
104+
105+
{/* Optional State Example */}
106+
<div>
107+
<h3>Optional State: Last Login Time</h3>
108+
<p>
109+
<strong>Current Value:</strong> {lastLoginTime || 'Never logged in'}
110+
</p>
111+
<p>
112+
<strong>State Key:</strong> <code>'user.lastLogin'</code>
113+
</p>
114+
<div style={{ marginTop: '12px', display: 'flex', gap: '8px' }}>
115+
<Button onClick={handleLogin} variant="outlined">
116+
Simulate Login
117+
</Button>
118+
<Button
119+
onClick={() => setLastLoginTime(undefined)}
120+
variant="outlined"
121+
disabled={!lastLoginTime}
122+
>
123+
Clear Login Time
124+
</Button>
125+
</div>
126+
</div>
127+
</div>
128+
</section>
129+
);
130+
};

0 commit comments

Comments
 (0)