Skip to main content

Form History

This guide explains how to use the form history system to implement undo/redo functionality and track form state changes over time.

What is Form History?

Form History is a powerful feature that automatically tracks form state changes, allowing users to undo and redo their actions. This is particularly useful for complex forms where users might make mistakes or want to revert changes.

📝 History System

The form history system automatically tracks form state changes and provides undo/redo functionality with configurable history depth and throttling.

Basic History Usage

Enabling History

🔄 Basic History

Enable history tracking by setting the historyItems prop on your Form component:

import React from 'react';
import { Form, useFormField, useFormHistory } from '@mapples/form';

const FormWithHistory = () => {
const onSubmit = (data) => {
console.log('Form submitted:', data);
};

return (
<Form
initialValues={{ name: '', email: '', message: '' }}
historyItems={20} // Keep 20 history items
onSubmit={onSubmit}
>
<NameField />
<EmailField />
<MessageField />
<HistoryControls />
</Form>
);
};

const NameField = () => {
const {
value,
error,
setValue,
touch
} = useFormField('name', '');

return (
<View>
<TextInput
value={value || ''}
onChangeText={setValue}
onBlur={() => touch('name')}
placeholder="Name"
/>
{error && (
<Text style={{ color: 'red' }}>{error}</Text>
)}
</View>
);
};

const EmailField = () => {
const {
value,
error,
setValue,
touch
} = useFormField('email', '');

return (
<View>
<TextInput
value={value || ''}
onChangeText={setValue}
onBlur={() => touch('email')}
placeholder="Email"
keyboardType="email-address"
/>
{error && (
<Text style={{ color: 'red' }}>{error}</Text>
)}
</View>
);
};

const MessageField = () => {
const {
value,
error,
setValue,
touch
} = useFormField('message', '');

return (
<View>
<TextInput
value={value || ''}
onChangeText={setValue}
onBlur={() => touch('message')}
placeholder="Message"
multiline
numberOfLines={4}
/>
{error && (
<Text style={{ color: 'red' }}>{error}</Text>
)}
</View>
);
};

const HistoryControls = () => {
const { canUndo, canRedo, undo, redo } = useFormHistory();

return (
<View style={{ flexDirection: 'row', gap: 10 }}>
<Button
title="Undo"
onPress={undo}
disabled={!canUndo}
/>
<Button
title="Redo"
onPress={redo}
disabled={!canRedo}
/>
</View>
);
};

History Controls Component

🎮 History Controls

Create history control components to allow users to navigate through form history:

import React from 'react';
import { View, Button } from 'react-native';
import { useFormHistory } from '@mapples/form';

const HistoryControls = () => {
const { canUndo, canRedo, undo, redo, historyLength, currentIndex } = useFormHistory();

return (
<View style={{ flexDirection: 'row', justifyContent: 'space-between', marginTop: 20 }}>
<Button
title="Undo"
onPress={undo}
disabled={!canUndo}
/>

<Button
title="Redo"
onPress={redo}
disabled={!canRedo}
/>

<Text>History: {currentIndex + 1} / {historyLength}</Text>
</View>
);
};

Advanced History Configuration

History Throttling

⚡ Performance Optimization

Use history throttling to prevent excessive history entries and improve performance:

import React from 'react';
import { Form, useField } from '@mapples/form';

const ThrottledForm = () => {
const onSubmit = (data) => {
console.log('Form submitted:', data);
};

return (
<Form
initialValues={{ title: '', content: '', tags: [] }}
historyItems={50} // Keep 50 history items
historyItemThrottle={500} // Throttle to 500ms between history entries
onSubmit={onSubmit}
>
<TitleField />
<ContentField />
<TagsField />
<HistoryControls />
</Form>
);
};

const TitleField = () => {
const titleField = useField('title', {
required: 'Title is required',
minLength: {
value: 5,
message: 'Title must be at least 5 characters',
},
});

return (
<View>
<TextInput
{...titleField}
placeholder="Article Title"
/>
{titleField.error && (
<Text style={{ color: 'red' }}>{titleField.error}</Text>
)}
</View>
);
};

const ContentField = () => {
const contentField = useField('content', {
required: 'Content is required',
minLength: {
value: 100,
message: 'Content must be at least 100 characters',
},
});

return (
<View>
<TextInput
{...contentField}
placeholder="Article Content"
multiline
numberOfLines={10}
/>
{contentField.error && (
<Text style={{ color: 'red' }}>{contentField.error}</Text>
)}
</View>
);
};

const TagsField = () => {
const tagsField = useField('tags', {
validate: (value) => {
if (!Array.isArray(value) || value.length === 0) {
return 'At least one tag is required';
}
return true;
},
});

return (
<View>
<TextInput
{...tagsField}
placeholder="Tags (comma separated)"
onChangeText={(text) => {
const tags = text.split(',').map(tag => tag.trim()).filter(tag => tag.length > 0);
tagsField.onChange(tags);
}}
/>
{tagsField.error && (
<Text style={{ color: 'red' }}>{tagsField.error}</Text>
)}
</View>
);
};

Filtering History Keys

🔍 Selective History

Use filterHistoryKeys to exclude certain fields from history tracking:

import React from 'react';
import { Form, useField } from '@mapples/form';

const FilteredHistoryForm = () => {
const onSubmit = (data) => {
console.log('Form submitted:', data);
};

return (
<Form
initialValues={{
name: '',
email: '',
message: '',
_canvasProps: {}, // Internal state that shouldn't be tracked
_tempData: null, // Temporary data that shouldn't be tracked
}}
historyItems={30}
historyItemThrottle={1000}
filterHistoryKeys={['_canvasProps', '_tempData']} // Exclude these from history
onSubmit={onSubmit}
>
<NameField />
<EmailField />
<MessageField />
<HistoryControls />
</Form>
);
};

const NameField = () => {
const nameField = useField('name', {
required: 'Name is required',
});

return (
<View>
<TextInput
{...nameField}
placeholder="Name"
/>
{nameField.error && (
<Text style={{ color: 'red' }}>{nameField.error}</Text>
)}
</View>
);
};

const EmailField = () => {
const emailField = useField('email', {
required: 'Email is required',
pattern: {
value: /^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$/i,
message: 'Invalid email address',
},
});

return (
<View>
<TextInput
{...emailField}
placeholder="Email"
keyboardType="email-address"
/>
{emailField.error && (
<Text style={{ color: 'red' }}>{emailField.error}</Text>
)}
</View>
);
};

const MessageField = () => {
const messageField = useField('message', {
required: 'Message is required',
});

return (
<View>
<TextInput
{...messageField}
placeholder="Message"
multiline
numberOfLines={4}
/>
{messageField.error && (
<Text style={{ color: 'red' }}>{messageField.error}</Text>
)}
</View>
);
};

History Hooks

useFormHistory

🔧 History Hook

Use the useFormHistory hook to access history functionality:

import React from 'react';
import { useFormHistory } from '@mapples/form';

const AdvancedHistoryControls = () => {
const {
canUndo,
canRedo,
undo,
redo,
historyLength,
currentIndex,
clearHistory,
jumpToIndex,
} = useFormHistory();

const handleJumpToStart = () => {
jumpToIndex(0);
};

const handleJumpToEnd = () => {
jumpToIndex(historyLength - 1);
};

const handleClearHistory = () => {
clearHistory();
};

return (
<View style={{ padding: 20 }}>
<View style={{ flexDirection: 'row', justifyContent: 'space-between', marginBottom: 10 }}>
<Button
title="Undo"
onPress={undo}
disabled={!canUndo}
/>

<Button
title="Redo"
onPress={redo}
disabled={!canRedo}
/>
</View>

<View style={{ flexDirection: 'row', justifyContent: 'space-between', marginBottom: 10 }}>
<Button
title="Jump to Start"
onPress={handleJumpToStart}
disabled={currentIndex === 0}
/>

<Button
title="Jump to End"
onPress={handleJumpToEnd}
disabled={currentIndex === historyLength - 1}
/>
</View>

<Button
title="Clear History"
onPress={handleClearHistory}
color="red"
/>

<Text style={{ textAlign: 'center', marginTop: 10 }}>
History: {currentIndex + 1} / {historyLength}
</Text>
</View>
);
};

useFormHistoryState

📊 History State

Use useFormHistoryState to access detailed history state information:

import React from 'react';
import { useFormHistoryState } from '@mapples/form';

const HistoryInfo = () => {
const {
history,
currentIndex,
canUndo,
canRedo,
historyLength,
isAtBeginning,
isAtEnd,
} = useFormHistoryState();

return (
<View style={{ padding: 20 }}>
<Text style={{ fontSize: 18, fontWeight: 'bold', marginBottom: 10 }}>
History Information
</Text>

<Text>Current Position: {currentIndex + 1} / {historyLength}</Text>
<Text>Can Undo: {canUndo ? 'Yes' : 'No'}</Text>
<Text>Can Redo: {canRedo ? 'Yes' : 'No'}</Text>
<Text>Is at Beginning: {isAtBeginning ? 'Yes' : 'No'}</Text>
<Text>Is at End: {isAtEnd ? 'Yes' : 'No'}</Text>

<Text style={{ marginTop: 10, fontWeight: 'bold' }}>
History Entries:
</Text>
{history.map((entry, index) => (
<Text key={index} style={{ marginLeft: 10 }}>
{index + 1}. {new Date(entry.timestamp).toLocaleTimeString()}
</Text>
))}
</View>
);
};

History Best Practices

Performance Optimization

⚡ Performance

Optimize history performance for better user experience:

import React, { useMemo } from 'react';
import { Form, useField } from '@mapples/form';

const OptimizedForm = () => {
// Use appropriate history items count based on form complexity
const historyItems = useMemo(() => {
// Simple forms: 10-20 items
// Complex forms: 30-50 items
// Very complex forms: 50-100 items
return 30;
}, []);

// Use throttling to prevent excessive history entries
const historyThrottle = useMemo(() => {
// Fast typing: 300-500ms
// Normal typing: 500-1000ms
// Slow typing: 1000-2000ms
return 500;
}, []);

return (
<Form
initialValues={{ name: '', email: '', message: '' }}
historyItems={historyItems}
historyItemThrottle={historyThrottle}
filterHistoryKeys={['_tempData', '_internalState']}
onSubmit={(data) => console.log('Form submitted:', data)}
>
<NameField />
<EmailField />
<MessageField />
<HistoryControls />
</Form>
);
};

Memory Management

💾 Memory Management

Manage memory usage by limiting history items and filtering unnecessary data:

import React from 'react';
import { Form, useField } from '@mapples/form';

const MemoryOptimizedForm = () => {
return (
<Form
initialValues={{
name: '',
email: '',
message: '',
_largeData: null, // Large data that shouldn't be tracked
_tempState: null, // Temporary state
_uiState: {}, // UI state that changes frequently
}}
historyItems={20} // Limit history items
historyItemThrottle={1000} // Throttle history entries
filterHistoryKeys={['_largeData', '_tempState', '_uiState']} // Filter out unnecessary data
onSubmit={(data) => console.log('Form submitted:', data)}
>
<NameField />
<EmailField />
<MessageField />
<HistoryControls />
</Form>
);
};

User Experience

👤 User Experience

Provide clear visual feedback for history operations:

import React, { useState } from 'react';
import { View, Button, Text, Alert } from 'react-native';
import { useFormHistory } from '@mapples/form';

const UserFriendlyHistoryControls = () => {
const { canUndo, canRedo, undo, redo, historyLength, currentIndex } = useFormHistory();
const [showFeedback, setShowFeedback] = useState(false);

const handleUndo = () => {
undo();
setShowFeedback(true);
setTimeout(() => setShowFeedback(false), 1000);
};

const handleRedo = () => {
redo();
setShowFeedback(true);
setTimeout(() => setShowFeedback(false), 1000);
};

return (
<View style={{ padding: 20 }}>
<View style={{ flexDirection: 'row', justifyContent: 'space-between', marginBottom: 10 }}>
<Button
title="↶ Undo"
onPress={handleUndo}
disabled={!canUndo}
color={canUndo ? '#007AFF' : '#CCCCCC'}
/>

<Button
title="↷ Redo"
onPress={handleRedo}
disabled={!canRedo}
color={canRedo ? '#007AFF' : '#CCCCCC'}
/>
</View>

<View style={{ alignItems: 'center', marginBottom: 10 }}>
<Text style={{ fontSize: 16, fontWeight: 'bold' }}>
{showFeedback ? 'Action Performed!' : 'History Navigation'}
</Text>
<Text style={{ color: '#666', marginTop: 5 }}>
Step {currentIndex + 1} of {historyLength}
</Text>
</View>

{!canUndo && !canRedo && (
<Text style={{ textAlign: 'center', color: '#999', fontStyle: 'italic' }}>
No history available
</Text>
)}
</View>
);
};

What's Next?

🔧 Hooks

Learn about all available hooks and how to use them effectively.

Hooks Guide →

🌐 Usage in React

Learn how to use Forms in React web applications.

React Usage →

📚 API Reference

Complete technical documentation for all Forms functions and components.

Full API →