@chain1/redux-toolkit
v1.0.1
Published
Redux Toolkit utilities and helpers for Stochain applications with AsyncStorage persistence
Maintainers
Readme
@chain1/redux-toolkit
Redux Toolkit utilities with built-in AsyncStorage persistence for React Native applications.
Features
- ✅ Easy Redux store setup
- ✅ Automatic AsyncStorage persistence
- ✅ Whitelist/Blacklist persistence control
- ✅ Debounced state saves
- ✅ Type-safe with TypeScript
- ✅ Async thunk helpers
- ✅ State rehydration on app start
- ✅ Utilities for clearing persisted data
Installation
npm install @chain1/redux-toolkitPeer Dependencies
npm install @reduxjs/toolkit react-redux @react-native-async-storage/async-storageUsage
Basic Store Setup
import { createStore } from '@chain1/redux-toolkit';
import { createSlice } from '@reduxjs/toolkit';
// Create slices
const counterSlice = createSlice({
name: 'counter',
initialState: { value: 0 },
reducers: {
increment: (state) => {
state.value += 1;
},
decrement: (state) => {
state.value -= 1;
},
},
});
const userSlice = createSlice({
name: 'user',
initialState: { name: '', email: '' },
reducers: {
setUser: (state, action) => {
state.name = action.payload.name;
state.email = action.payload.email;
},
},
});
// Create store with persistence
const store = createStore({
reducer: {
counter: counterSlice.reducer,
user: userSlice.reducer,
},
persist: {
key: 'root',
storage: AsyncStorage,
whitelist: ['user'], // Only persist user slice
},
});
export { store };
export const { increment, decrement } = counterSlice.actions;
export const { setUser } = userSlice.actions;With Provider
import React from 'react';
import { Provider } from 'react-redux';
import { store } from './store';
function App() {
return (
<Provider store={store}>
<YourApp />
</Provider>
);
}Using in Components
import React from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { increment, decrement } from './store';
function Counter() {
const count = useSelector((state: any) => state.counter.value);
const dispatch = useDispatch();
return (
<View>
<Text>Count: {count}</Text>
<Button title="+" onPress={() => dispatch(increment())} />
<Button title="-" onPress={() => dispatch(decrement())} />
</View>
);
}API Reference
createStore(config: StoreConfig)
Create Redux store with optional persistence.
StoreConfig:
reducer(object, required): Redux reducersmiddleware(array, optional): Additional middlewarepersist(PersistConfig, optional): Persistence configurationdevTools(boolean, optional): Enable Redux DevTools (default: true)
PersistConfig:
key(string, required): AsyncStorage keystorage(AsyncStorage, required): Storage enginewhitelist(string[], optional): Slices to persistblacklist(string[], optional): Slices to exclude from persistenceversion(number, optional): State version for migrations
const store = createStore({
reducer: {
user: userReducer,
settings: settingsReducer,
},
persist: {
key: 'app-state',
storage: AsyncStorage,
whitelist: ['user', 'settings'],
},
});createAsyncThunk(typePrefix, payloadCreator)
Create async action with loading states.
import { createAsyncThunk } from '@chain1/redux-toolkit';
const fetchUser = createAsyncThunk(
'user/fetch',
async (userId: string) => {
const response = await api.getUser(userId);
return response.data;
}
);
// Dispatch
dispatch(fetchUser('123'));createPersistedSlice(config)
Create a slice with automatic AsyncStorage persistence.
import { createPersistedSlice } from '@chain1/redux-toolkit';
const { name, initialState, reducers, loadInitialState, saveState } = createPersistedSlice({
name: 'settings',
initialState: { theme: 'dark', language: 'en' },
reducers: {
setTheme: (state, action) => {
state.theme = action.payload;
},
},
storageKey: 'app-settings',
});
// Load on app start
loadInitialState().then((state) => {
store.dispatch({ type: 'settings/rehydrate', payload: state });
});clearPersistedState(key: string): Promise<void>
Clear persisted state from AsyncStorage.
import { clearPersistedState } from '@chain1/redux-toolkit';
// Clear all persisted data
await clearPersistedState('root');getAllKeys(): Promise<string[]>
Get all AsyncStorage keys.
import { getAllKeys } from '@chain1/redux-toolkit';
const keys = await getAllKeys();
console.log('Stored keys:', keys);Advanced Examples
Selective Persistence
// Persist only specific slices
const store = createStore({
reducer: {
auth: authReducer,
cache: cacheReducer,
ui: uiReducer,
},
persist: {
key: 'app',
storage: AsyncStorage,
whitelist: ['auth'], // Only persist auth
},
});Blacklist Persistence
// Persist everything except UI state
const store = createStore({
reducer: {
auth: authReducer,
data: dataReducer,
ui: uiReducer,
},
persist: {
key: 'app',
storage: AsyncStorage,
blacklist: ['ui'], // Don't persist UI
},
});Custom Middleware
import { createStore } from '@chain1/redux-toolkit';
const loggerMiddleware = (store) => (next) => (action) => {
console.log('Dispatching:', action);
const result = next(action);
console.log('Next state:', store.getState());
return result;
};
const store = createStore({
reducer: { /* ... */ },
middleware: [loggerMiddleware],
});TypeScript Integration
import { createStore } from '@chain1/redux-toolkit';
import { TypedUseSelectorHook, useDispatch, useSelector } from 'react-redux';
// Define RootState type
const store = createStore({
reducer: {
user: userReducer,
settings: settingsReducer,
},
});
export type RootState = ReturnType<typeof store.getState>;
export type AppDispatch = typeof store.dispatch;
// Typed hooks
export const useAppDispatch = () => useDispatch<AppDispatch>();
export const useAppSelector: TypedUseSelectorHook<RootState> = useSelector;
// Usage
function MyComponent() {
const user = useAppSelector((state) => state.user);
const dispatch = useAppDispatch();
// Full type safety!
}Reset All Data
import { clearPersistedState, getAllKeys } from '@chain1/redux-toolkit';
async function resetApp() {
// Clear all persisted Redux data
await clearPersistedState('root');
// Or clear all AsyncStorage
const keys = await getAllKeys();
await AsyncStorage.multiRemove(keys);
// Reset store to initial state
store.dispatch({ type: 'RESET' });
}Persistence Behavior
Auto-Save
State is automatically saved to AsyncStorage:
- Debounced by 500ms to avoid excessive writes
- Only saves whitelisted slices
- Handles JSON serialization errors gracefully
Auto-Load
State is automatically loaded on app start:
- Rehydrates store before first render
- Merges with initial state
- Handles corrupt data gracefully
Migration Support
const store = createStore({
reducer: { /* ... */ },
persist: {
key: 'root',
storage: AsyncStorage,
version: 2, // Increment on breaking changes
},
});Best Practices
- Whitelist critical data only: Don't persist UI state or cached data
- Use TypeScript: Define RootState and AppDispatch types
- Handle rehydration: Show loading screen during state restoration
- Version your state: Increment version on schema changes
- Clear on logout: Clear persisted auth data on logout
Troubleshooting
State not persisting
// Check whitelist/blacklist configuration
persist: {
key: 'root',
storage: AsyncStorage,
whitelist: ['user'], // Make sure slice name matches
}State not rehydrating
// Ensure Provider wraps app
<Provider store={store}>
<App />
</Provider>TypeScript errors
// Define proper types
export type RootState = ReturnType<typeof store.getState>;License
MIT
