Following the tradition of ridiculously titled Flux variations, I'm proud to announce Flurx.
Flux using RxJS, advocating but not strictly enforcing immutable data structures.
It's a very thin wrapper around Rx.Subject
for Actions and Rx.BehaviorSubject
for Stores,
basically adding only two methods:
- waitFor on Actions
- register on Stores
In a nutshell:
- A Store is modelling a value that is changing over time (i.e. BehaviorSubject)
- A Store can subscribe to many Actions, each with a handler
- A handler receives the call parameters of the action and produces a new value of the store.
- React components can subscribe to Stores
- React components can call Actions
npm install flurx
import React from 'react';
import {Store, Action} from 'flurx';
const LoginAction = Action.create();
const LoginActionSuccess = Action.create();
const LoginActionFailure = Action.create();
class LoginStore extends Store {
constructor() {
super({
isLoggedIn: false,
username: null,
warn: null
});
this.register(LoginAction, this.onLogin);
this.register(LoginActionSuccess, this.onLoginSuccess);
this.register(LoginActionFailure, this.onLoginFailure);
}
onLogin(store, username, password) {
if (!store.isLoggedIn) {
getJSON('/login', {username, password})
.then(LoginActionSuccess)
.catch(LoginActionFailure);
return Object.assign(store, {
isLoggedIn: true,
username,
warn: null
});
}
return store;
}
onLoginSuccess(store, result) {
return Object.assign(store, {
isLoggedIn: true,
username: result.username
warn: null
});
}
onLoginFailure(store, err) {
return Object.assign(store, {
isLoggedIn: false,
username: null,
warn: err.message
})
}
}
const loginStore = new LoginStore();
const LoginComponent = React.createClass({
getInitialState() {
return loginStore.getValue();
},
componentDidMount() {
loginStore.subscribe(store => {
this.setState(store);
});
},
onSubmit(e) {
e.preventDefault();
const username = this.refs.username.getValue().trim();
const password = this.refs.password.getValue().trim();
if (!username || !password) {
return;
}
LoginAction(username, password);
},
render() {
return (
!this.state.isLoggedIn ?
<form method="GET" action="/login" onSubmit={this.onSubmit}>
{this.state.warn != null ? <p>{this.state.warn}</p> : null}
<input ref="username" name="username" type="text"/>
<input ref="password" name="password" type="password"/>
<button type="submit">Login</button>
</form> :
<p>Welcome, {this.state.username}.</p>
);
}
});