react-obj-view
Version:
A powerful React component for visualizing JavaScript objects and data structures with an interactive, expandable tree view
377 lines (306 loc) • 9.83 kB
Markdown
# React Object View
A powerful and flexible React component for visualizing JavaScript objects and data structures with an interactive, expandable tree view. Perfect for debugging, data inspection, and creating developer tools.
## 🌟 Live Demo
**[Try the Interactive Demo →](https://vothanhdat.github.io/react-obj-view/)**
Experience all features hands-on including custom renderers, keyword styling, and configurable highlighting!
> **Note**: If the demo link shows "404", please wait a few minutes for GitHub Pages to deploy, or check that GitHub Pages is enabled in repository settings.
## ✨ Features
- 🌳 **Interactive Tree View**: Expand and collapse object properties with intuitive click interactions
- 🎯 **Smart Type Rendering**: Intelligent display for all JavaScript types (objects, arrays, functions, promises, maps, sets, etc.)
- 📦 **Automatic Grouping**: Groups large arrays and objects for optimal performance and readability
- 🔄 **Circular Reference Safe**: Safely handles circular references without infinite loops
- ⚡ **Performance Optimized**: Efficient rendering with lazy loading and change detection
- 🎨 **Customizable Styling**: Built-in CSS with full customization support
- � **Custom Renderers**: Register custom components for specific data types or constructor functions
- 💡 **Keyword Highlighting**: Special styling for boolean values, null, undefined with keyword badges
- �📱 **TypeScript Ready**: Complete TypeScript support with proper type definitions
- 🔍 **Developer Friendly**: Perfect for debugging, logging, and data inspection
- ⚙️ **Configurable Highlighting**: Control change detection and flash highlighting behavior
## 🚀 Quick Start
### Installation
```bash
npm install react-obj-view
# or
yarn add react-obj-view
```
### Basic Usage
```tsx
import React from 'react';
import { ObjectView } from 'react-obj-view';
// Import the CSS styles
import 'react-obj-view/dist/react-obj-view.css';
const App = () => {
const data = {
user: {
name: "John Doe",
age: 30,
preferences: {
theme: "dark",
notifications: true
}
},
items: ["apple", "banana", "cherry"],
metadata: {
created: new Date(),
tags: new Set(["react", "typescript"])
}
};
return (
<div>
<h1>Data Inspector</h1>
<ObjectView
value={data}
name="appData"
expandLevel={2}
/>
</div>
);
};
```
## 📖 Examples
### Controlling Expansion
```tsx
// Expand all levels (use carefully with large objects)
<ObjectView value={data} expandLevel={true} />
// Expand first 3 levels
<ObjectView value={data} expandLevel={3} />
// Start collapsed
<ObjectView value={data} expandLevel={false} />
```
### Handling Different Data Types
```tsx
const complexData = {
// Primitives
name: "React Object View",
version: 1.0,
isActive: true,
// Collections
users: ["alice", "bob", "charlie"],
userMap: new Map([
["alice", { role: "admin" }],
["bob", { role: "user" }]
]),
tags: new Set(["react", "typescript", "visualization"]),
// Advanced types
createdAt: new Date(),
pattern: /[a-z]+/gi,
callback: (x) => x * 2,
asyncData: Promise.resolve("Loaded successfully"),
// Nested structures
config: {
api: {
baseUrl: "https://api.example.com",
timeout: 5000,
retries: 3
},
features: {
darkMode: true,
notifications: false
}
}
};
<ObjectView
value={complexData}
name="appConfig"
expandLevel={2}
objectGrouped={50} // Group objects with 50+ properties
arrayGrouped={20} // Group arrays with 20+ items
/>
```
### Real-World Use Cases
#### API Response Debugging
```tsx
const apiResponse = {
status: 200,
data: {
users: [
{ id: 1, name: "Alice", email: "alice@example.com" },
{ id: 2, name: "Bob", email: "bob@example.com" }
],
pagination: {
page: 1,
totalPages: 5,
totalItems: 87
}
},
headers: {
"content-type": "application/json",
"x-request-id": "abc-123"
}
};
<ObjectView value={apiResponse} name="API Response" expandLevel={2} />
```
#### State Management Debugging
```tsx
const [appState, setAppState] = useState({
user: { name: "John", preferences: {...} },
ui: { theme: "dark", sidebarOpen: true },
data: { items: [...], loading: false }
});
// Visualize state changes
<ObjectView
value={appState}
name="Application State"
expandLevel={1}
/>
```
## 🎛️ API Reference
### Props
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| `value` | `any` | **required** | The data to visualize |
| `name` | `string` | `undefined` | Display name for the root object |
| `style` | `CSSProperties` | `undefined` | Custom styles for the container |
| `expandLevel` | `number \| boolean` | `false` | Initial expansion: `true` (all), `false` (none), or depth number |
| `objectGrouped` | `number` | `25` | Group objects with more than N properties |
| `arrayGrouped` | `number` | `10` | Group arrays with more than N elements |
| `customRender` | `Map<Constructor, React.FC>` | `undefined` | Custom renderers for specific types |
| `highlightUpdate` | `boolean` | `true` | Enable/disable change detection highlighting |
### Supported Data Types
- ✅ **Primitives**: `string`, `number`, `boolean`, `null`, `undefined`, `symbol`, `bigint`
- ✅ **Objects**: Plain objects, class instances, nested structures
- ✅ **Arrays**: Regular arrays, typed arrays, sparse arrays
- ✅ **Functions**: Arrow functions, regular functions, methods
- ✅ **Built-ins**: `Date`, `RegExp`, `Error`, `Map`, `Set`, `Promise`
- ✅ **Special Cases**: Circular references, long strings, large collections
## 🎨 Styling
The component comes with sensible defaults but is fully customizable:
```css
/* Container */
.jv-root {
font-family: 'Monaco', 'Menlo', monospace;
font-size: 12px;
}
/* Property names */
.jv-name {
color: #881391;
font-weight: bold;
}
/* Values by type */
.jv-field-string .jv-value { color: #c41a16; }
.jv-field-number .jv-value { color: #1c00cf; }
.jv-field-boolean .jv-value { color: #aa0d91; }
/* Keyword badges (null, undefined, true, false) */
.jv-keyword {
font-size: 0.85em;
padding-inline: 0.6em;
margin-inline: 0.3em;
padding-block: 0.05em;
border-radius: 0.2em;
text-transform: uppercase;
font-weight: bold;
background-color: color-mix(in srgb, currentColor 20%, var(--jv-bg-color));
}
/* Interactive elements */
.jv-cursor { cursor: pointer; }
.jv-cursor:hover { background-color: #f0f0f0; }
/* Change highlighting */
.change-flash {
background-color: #fff3cd;
transition: background-color 0.5s ease;
}
```
## 🔧 Advanced Features
### Change Detection
Values that change between renders are automatically highlighted:
```tsx
const [counter, setCounter] = useState({ count: 0, lastUpdated: Date.now() });
const increment = () => {
setCounter(prev => ({
count: prev.count + 1,
lastUpdated: Date.now()
}));
};
return (
<div>
<button onClick={increment}>Increment</button>
<ObjectView value={counter} expandLevel={true} />
</div>
);
```
### Performance with Large Data
```tsx
// Efficiently handles large datasets
const largeDataset = {
users: new Array(1000).fill(null).map((_, i) => ({
id: i,
name: `User ${i}`,
email: `user${i}@example.com`
})),
metadata: {
total: 1000,
generated: new Date()
}
};
<ObjectView
value={largeDataset}
arrayGrouped={50} // Show 50 items before grouping
objectGrouped={100} // Show 100 properties before grouping
expandLevel={1} // Only expand first level initially
/>
```
### Custom Renderers
Register custom components for specific data types:
```tsx
import React from 'react';
import { ObjectView } from 'react-obj-view';
// Custom renderer for User class instances
class User {
constructor(public name: string, public email: string) {}
}
const UserRenderer = ({ value, name, displayName, separator = ":" }) => (
<div className="custom-user-view">
{displayName && <span className="jv-name">{name}</span>}
{displayName && <span>{separator}</span>}
<span className="user-badge">👤 {value.name}</span>
<span className="user-email">({value.email})</span>
</div>
);
// Create custom render map
const customRenderers = new Map([
[User, UserRenderer]
]);
const data = {
currentUser: new User("John Doe", "john@example.com"),
admin: new User("Admin", "admin@example.com")
};
<ObjectView
value={data}
customRender={customRenderers}
expandLevel={2}
/>
```
### Controlling Change Highlighting
```tsx
// Disable change highlighting for performance
<ObjectView
value={frequentlyChangingData}
highlightUpdate={false}
expandLevel={1}
/>
// Enable highlighting (default behavior)
<ObjectView
value={data}
highlightUpdate={true}
expandLevel={1}
/>
```
## 💡 Tips & Best Practices
1. **Performance**: Use appropriate `expandLevel` values for large objects
2. **Grouping**: Adjust `arrayGrouped` and `objectGrouped` based on your data size
3. **Debugging**: Perfect for inspecting API responses, state changes, and complex data structures
4. **Development**: Great for creating admin panels, debug tools, and data browsers
## 🌐 Browser Support
- ✅ Chrome/Edge 88+
- ✅ Firefox 85+
- ✅ Safari 14+
- ✅ React 19+
- ✅ TypeScript 5.0+
## 📝 License
MIT License - see [LICENSE](LICENSE) file for details.
## 🤝 Contributing
Contributions are welcome! Please feel free to submit issues and pull requests.
## 🔗 Links
- [GitHub Repository](https://github.com/vothanhdat/react-obj-view)
- [Issue Tracker](https://github.com/vothanhdat/react-obj-view/issues)
- [NPM Package](https://www.npmjs.com/package/react-obj-view)