First of all: Why is it called "DUIX"? The x
at the end is obvious: Because it's a state manager. If you make your own state manager and you don't call it with an x
at the end, please, don't do a state manager. On another hand the dui
means: DON'T USE IT
. So, you are already warned.
With examples. People need examples!
duix.get('user')
: Returns (it's NOT a promise) theuser
value.duix.set('user', { name: 'Noel' })
: This set theuser
value. it can be ab Object, Array, Null, whatever.duix.subscribe('user', (newValue, oldValue) => { /* ... */ })
: Subscribe that callback (the second parameter) to every change made inuser
. That function is gonna be called every timeduix.set('user', whatever)
is called. This function also returns a function that if you call it, you unsubcribe to the changes (example below).
Here the unsubscribe example:
// Subscribe
const goodBye = duix.subscribe('user', (newValue, oldValue) => {
/* ... */
});
// Unsubscribe
goodBye();
Because if you saw (if not, you should) all the courses, tweets, videos and blogs from our almighty frontend community, you should already learned that EVERYTHING SHOULD BE DECLARATIVE. And this, my friend, is not declarative at all (and I hope to keep it as it is).
So...
Because some most of the current State Managers libs add too unnecessary complexity (even in the learning curve, or arch, or high coupling between components).
The idea of duix
is to reuse some old knowledge to solve only one simple problem: Keep 2 components on sync.
There are 2 things that I keep on mind while working:
- KISS: Keep it simple, stupid.
- Pareto principle: The 80% and 20%. The 80% of your bugs, are gonna be always the same 2 or 3 issues that you always see in every project.
The KISS patter is very clear, but I believe the Pareto principle deserves more details:
I believe that if you added a State Manager in 10 projects, you may added it 8 times just to solve 1 issue: "Keep a couple of vars on sync between components", and also 2 times that you solves tons of issues that it absolutelly worth it. But, what about those 8 times that you added, let's say, Redux, only to keep 1 var on sync? You only needed a global state var and a callback, but you added Redux (complexity, a lot of complexity my friend).
The idea of duix
is to cover those 8 times that you added Redux only because you needed to keep on sync vars between components. Just that. There is a global state
object, that you set
values, or get
values, and you can subscribe
or unsubscribe
, and every time someone set
a new value, all the subscribers are gonna be called receiving the new and the old value.
I'm a React dev, and I used Redux a couple of times. After creating this tool (I was using it during one whole year), I used this tool in 5 projects, and I had to use Redux in only 1.
If your team is not feeling very well with the current State Managers complexity, I'd say that you should try this tool. But, due to it's not in the declarative hype
, I'd preffer to say: DON'T USE IT!
duix
just have a state that is just a plain object, and some listeners (publish-subscribers) that are gonna be called every time the subscribed-value change.
Buttons
component is gonna add or subtract.Viewer
component is gonna show the value
// index.js
import duix from 'duix';
// Set `null` as default `user` value
duix.set('githubStars', 0);
class App extends Component {
// ...
}
// Buttons.js
import duix from 'duix';
class Buttons extends Component {
handleAdd = () => {
const currentValue = duix.get('githubStars');
duix.set('githubStars', currentValue + 1);
};
handleSubtract = () => {
const currentValue = duix.get('githubStars');
duix.set('githubStars', currentValue - 1);
};
// ...
}
// Viewer.js
import duix from 'duix';
class Viewer extends Component {
unsubscribe = [];
state = {
githubStars: duix.get('githubStars') // get initial value
};
componentDidMount() {
this.unsubscribe[0] = duix.subscribe('githubStars', this.onStarsChange);
}
componentWillUnmount() {
this.unsubscribe[0]();
}
onStarsChange = (githubStars) => {
this.setState({ githubStars });
};
render() {
return (
<div className="Viewer">
{this.state.githubStars} stars
</div>
);
}
}
So, could you understand what happened there? Only 3 things on duix
:
- Someone needs to set the default value
- Someone is gonna get the initial value, and also
subscribe
to any change - Someone is gonna
set
the new value every time it have to be changed.
- The main file in the app defines the initial value for the
user
object. - The
Header
component is subscribed to the changes ofuser
(because if theuser
object is notnull
, it's because the user is logged). - The
Login
component is gonna call a function that is gonna do the API call to check if the credentials are OK. - The
LogOut
component is gonna logout the user. ๐คท
The code:
// index.js
import duix from 'duix';
// Set `null` as default `user` value
duix.set('user', null);
class App extends Component {
// ...
}
// Login.js
import duix from 'duix';
// Let's suppose this `actions` is an object with all the functions necessary to login an user
import { loginWithCredentials } from 'actions';
class Login extends Component {
handleLogin = (email, password) => {
// The `Login` component is not gonna change the `user` object. Instead, the `loginWithCredentials` is gonna do it.
loginWithCredentials(email, password);
};
// ...
}
// Logout.js
import duix from 'duix';
class Logout extends Component {
handleLogout = () => {
duix.set('user', null);
};
// ...
}
// actions.js
import duix from 'duix';
export default {
loginWithCredentials: (email, password) => {
fetch(
'http://example.com/api/login',
// ...
).then(r => r.json())
.then((user) => {
/**
* Whatever the backend send us, let's set it.
*
* Let's suppose the backend send `null` if the credentials were wrong,
* or the proper `user` object if the credentials were OK.
*/
duix.set('user', user);
});
}
};
// Header.js
import duix from 'duix';
class Header extends Component {
unsubscribe = [];
state = {
user: null
};
componentDidMount() {
// Let's subscribe to the `user` changes
this.unsubscribe[0] = duix.subscribe('user', this.onUserChange);
}
componentWillUnmount() {
// Let's unsubscribe.
this.unsubscribe[0]();
}
onUserChange = (user) => {
this.setState({ user });
};
render() {
return (
<div className="Header">
{ this.state.user && `Hello ${this.state.user.name}` }
</div>
);
}
}
So, could you understand what happened there? Only 3 things on duix
:
- Someone needs to set the default value
- Someone is gonna
subscribe
to a value change, or unsubscribe when component unmount. - Someone is gonna
set
the new value every time it changes
"That's all, folks"
PS: 10 minutes ago it was Christmas. This is my gift for te community.