Stateless
Your component layer ends up becoming stateless, and only responsible for accepting props and rendering them.
Redux
JavaScript
RxJS
Proppy
React
Vue.js
Preact
import React from 'react';
import { compose, withProps, withState } from 'proppy';
import { attach } from 'proppy-react';
const P = compose(
withProps({ foo: 'foo value' }),
withState('counter', 'setCounter', 0)
);
function MyComponent({ foo, counter, setCounter }) {
return (
<div>
<p>Foo: {foo}</p>
<p>Counter: {counter}</p>
<button onClick={() => setCounter(counter + 1)}>
Increment
</button>
</div>
);
}
export default attach(P)(MyComponent);
import React from 'react';
class MyComponent extends React.Component {
constructor(props) {
super(props);
this.state = {
foo: 'foo value',
counter: 0
};
this.handleIncrement = this.handleIncrement.bind(this);
}
handleIncrement() {
const currentCounter = this.state.counter;
this.setState({
counter: currentCounter + 1
});
}
render() {
const { foo, counter } = this.state;
return (
<div>
<p>Foo: {foo}</p>
<p>Counter: {counter}</p>
<button onClick={this.handleIncrement}>
Increment
</button>
</div>
);
}
}
export default MyComponent;
See detailed example here.
import { compose, withProps, withState } from 'proppy';
import { attach } from 'proppy-vue';
const P = compose(
withProps({ foo: 'foo value' }),
withState('counter', 'setCounter', 0)
);
const MyComponent = {
props: ['foo', 'counter', 'setCounter'],
render(h) {
const { foo, counter, setCounter } = this;
return (
<div>
<p>Foo: {foo}</p>
<p>Counter: {counter}</p>
<button onClick={() => setCounter(counter + 1)}>
Increment
</button>
</div>
);
},
}
export default attach(P)(MyComponent);
const MyComponent = {
data: function () {
return {
counter: 0
};
},
methods: {
handleIncrement: function () {
const currentCounter = this.counter;
this.counter = currentCounter + 1;
}
},
render(h) {
return (
<div>
<p>Counter: {this.counter}</p>
<button onClick={this.handleIncrement}>
Increment
</button>
</div>
);
}
};
export default MyComponent;
See detailed example here.
import { h } from 'preact';
import { compose, withProps, withState } from 'proppy';
import { attach } from 'proppy-preact';
const P = compose(
withProps({ foo: 'foo value' }),
withState('counter', 'setCounter', 0)
);
function MyComponent({ foo, counter, setCounter }) {
return (
<div>
<p>Foo: {foo}</p>
<p>Counter: {counter}</p>
<button onClick={() => setCounter(counter + 1)}>
Increment
</button>
</div>
);
}
export default attach(P)(MyComponent);
import { h } from 'preact';
class MyComponent extends Preact.Component {
constructor(props) {
super(props);
this.state = {
foo: 'foo value',
counter: 0
};
this.handleIncrement = this.handleIncrement.bind(this);
}
handleIncrement() {
const currentCounter = this.state.counter;
this.setState({
counter: currentCounter + 1
});
}
render(props, state) {
const { foo, counter } = state;
return (
<div>
<p>Foo: {foo}</p>
<p>Counter: {counter}</p>
<button onClick={this.handleIncrement}>
Increment
</button>
</div>
);
}
}
export default MyComponent;
See further guides here.
import React from 'react';
import { withStore } from 'proppy-redux';
import { attach } from 'proppy-react';
import { incrementCounter } from '../actions/counter';
const P = withStore(
state => ({ counter: state.counter.value }),
{ increment: incrementCounter }
);
function MyComponent({ counter, increment }) {
return (
<div>
<p>Counter: {counter}</p>
<button onClick={increment}>
Increment
</button>
</div>
);
}
export default attach(P)(MyComponent);
import React from 'react';
import { connect } from 'react-redux';
import { incrementCounter } from '../actions/counter';
function mapState(state) {
return {
counter: state.counter.value
};
}
const mapDispatch = {
increment: incrementCounter
};
function MyComponent({ counter, increment }) {
return (
<div>
<p>Counter: {counter}</p>
<button onClick={increment}>
Increment
</button>
</div>
);
}
export default connect(mapState, mapDispatch)(MyComponent);
See detailed example here.
import React from 'react';
import { interval } from 'rxjs';
import { map } from 'rxjs/operators';
import { withStream } from 'proppy-rx';
import { attach } from 'proppy-react';
const P = withStream(incomingProps$ => {
return interval(1000).pipe(
map(n => ({ interval: n }))
);
});
function MyComponent({ interval }) {
return <p>Interval: {interval}</p>;
}
export default attach(P)(MyComponent);
import React from 'react';
import { interval } from 'rxjs';
import { map } from 'rxjs/operators';
class MyComponent extends React.Component {
constructor(props) {
super(props);
this.state = {
interval: 0
};
}
componentDidMount() {
const interval$ = interval(1000).pipe(
map(n => ({ interval: n }))
);
this._rxSubscription = $interval.subscribe(intervalProps => {
this.setState(intervalProps);
});
}
componentWillUnmount() {
this._rxSubscription.unsubscribe();
}
render() {
const { interval } = this.props;
return <p>Interval: {interval}</p>;
}
}
export default MyComponent;
See detailed example here.
import { compose, withProps, withState } from 'proppy';
const P = compose(
withProps({ foo: 'foo value' }),
withState('counter', 'setCounter', 0)
);
const p = P();
console.log(p.props);
// {
// foo: 'foo value',
// counter: 0,
// setCounter: Function
// }
p.setCounter(5);
console.log(p.props);
// {
// foo: 'foo value',
// counter: 5,
// setCounter: Function
// }
const unsubscribe = p.subscribe(props => console.log(props));
unsubscribe();
// without proppy
See quick start guide here.
Stateless
Your component layer ends up becoming stateless, and only responsible for accepting props and rendering them.
Interoperable
Integrating other libraries to your components layer becomes a breeze with the suite of functions that Proppy provides you.
Functional
With your props being composed in functions, they become easier to expand as your requirements grow.
Testing
With clear separation between props generation and components, you can now unit test them separately with ease.
Providers
With Proppy's providers, you can set application-wide global object accessible anywhere in your components tree.
Freedom
Since Proppy connects to your favourite UI rendering library, you have the freedom to switch with minimal effort.
Sounds good? Let's get started!