React State Management without Redux
React RetiX
This package is used for state management, it is not intended to become an alternative to Redux. It just provides a different approach to state management in React.
If you’re looking for a simple, flexible, effective way to manage the global state of your React application, this package is for you. If you’re new to Redux, you’re confused with a lot of its concepts such as the store
, reducer
, action
, middleware
– Alright, go ahead with React Rx.
Let’s take a look at the detail below:
Competitive benefits:
- Light-weight
- Easy to use
- Simple of architecture
- Can use any where in your react application, not only in component
Install
npm i react-retix
Built-in
MasterStore
- For registering a store, the same concept as
createStore
inRedux
useSubscriber
- For watching state, the same concept as
useSelector
inReact Hooks + Redux
useEmitter
- For doing action, updating state, the same concept as
useDispatch
inReact Hooks + Redux
Usage
Register
import React, { useState } from 'react';
import { MasterStore } from 'react-retix';
new MasterStore({ state });
const App = () => {
return <></>
};
const rootElement = document.getElementById('root')
ReactDOM.render(<App />, rootElement)
Watch state
Root (Master store)
import React from 'react';
import { useSubscriber } from 'react-retix';
const App = () => {
const masterStore = useSubscriber();
return <></>
};
Children
import React from 'react';
import { useSubscriber } from 'react-retix';
const LoadingIndicator = () => {
const isLoading = useSubscriber('page.isLoading');
return isLoading && <Spinner />
};
Update state
Inside component
import React from 'react';
import { useSubscriber } from 'react-retix';
const PostReaction = (post) => {
const { isAuthenticated } = useSubscriber('user');
const doLike = () => {
useEmitter({ isLiked: true });
}
return (
<div>
{
isAuthenticated ? <button onClick={onLike}>Like</button> : <button>Sign in</button>
}
</div>
)
}
Outside component (Either Service, utils or othes)
import { useEmitter } from 'react-retix';
class PostService {
constructor () {
//
}
getPost () {
this.api.get('posts').then((data) => {
useEmitter({ post: data });
}).catch((err) => {
useEmitter({ errors: err });
}).finally(() => {
useEmitter({ isLoading: false });
});
}
}
Others
The usage of tring
To update a state, you can specify the path of an object
useEmitter(val, 'level1.level2.level3.level4');
instead of
useEmitter({
level1: {
level2: {
level3: {
level4: val
}
}
}
});
Both of them works the same, choose a comfortable one base on your use-case.
Deep merge objects
Highly noted that, due to data integrity purpose we decided to use deep merge for updating objects, for example:
Current state
{
level1: {
level21: true,
level22: 'xyz',
level23: {
level3: null
}
}
}
Update the state with new data
useEmitter({
level1: {
level21: false
}
});
The result would be
{
level1: {
level21: false, // updated with new value
level22: 'xyz', // not be removed
level23: { // not be removed
level3: null
}
}
}
It means all attributes of an object will be persisted as initial values, unless you try to force to remove them all by setting it value to empty object {}
or null
Force to remove all attributes
useEmitter({
level1: {} // or null also works
});
The result would be
{
level1: {}
};
Services
React RetiX
recommend you to use service to handle business logic of your application.
If you have familiared with Redux
, you can imagine that services is the same as what reducers
do in Redux architecture.
Please checkout the example for further detail.
Contributing
Pull requests are always welcome!
Contributors ✨
Thanks goes to these wonderful people (emoji key):
Vix Nguyen ? ? ? |
Vi Nguyen H.T. ? ? |
This project follows the all-contributors specification. Contributions of any kind welcome!