

@redux/cbd context package that allow you to write much shorter reactive storages instead of redux.
Installation
For current ongoing package:
npm install --save @redux-cbd/context
Important:
- Package uses 'expirementalDecorators' features (disabled by default for TypeScript transpiler).
What is inside
Example (wiki contains more explanations):
Application entrypoint.
import * as React from "react";
import {render} from "react-dom";
import {EntryPoint} from "@redux-cbd/utils";
import {MainView, IMainViewExternalProps} from "./view/MainView";
@EntryPoint()
export class Application {
public static main(): void {
render(<div>
<MainView someLabelFromExternalProps={ "First component." } { ...{} as IMainViewExternalProps }/>
<MainView someLabelFromExternalProps={ "Second component." } { ...{} as IMainViewExternalProps }/>
</div>, document.getElementById("application-root"));
}
}
Context store reexport and signleton creation.
import {AuthContextManager, IAuthContext} from "./AuthContextManager";
export const authContextManager: AuthContextManager = new AuthContextManager();
export {AuthContextManager, IAuthContext} from "./AuthContextManager";
Context and handlers declaration.
import {Bind} from "@redux-cbd/utils";
import {ReactContextManager} from "@redux-cbd/context";
export interface IAuthContext {
authActions: {
setUser: (user: string) => void;
setUserAsync: () => Promise<void>;
changeAuthenticationStatus: () => void;
};
authState: {
isAuthenticated: boolean;
user: string;
};
}
export class AuthContextManager extends ReactContextManager<IAuthContext> {
protected readonly context: IAuthContext = {
authActions: {
changeAuthenticationStatus: this.changeAuthenticationStatus,
setUserAsync: this.setUserAsync,
setUser: this.setUser
},
authState: {
isAuthenticated: true,
user: "anonymous"
}
};
@Bind()
public changeAuthenticationStatus(): void {
this.context.authState = { ...this.context.authState, isAuthenticated: !this.context.authState.isAuthenticated };
this.update();
}
@Bind()
public setUser(user: string): void {
this.context.authState = { ...this.context.authState, user };
this.update();
}
@Bind()
public setUserAsync(): Promise<void> {
return new Promise((resolve) => {
setTimeout(() => {
this.context.authState = {...this.context.authState, user: "user-" + Math.floor(Math.random() * 10000)};
this.update();
resolve();
}, 3000)
});
}
}
Connected component.
import * as React from "react";
import {PureComponent} from "react";
import {Consume, Provide} from "@redux-cbd/context";
import {authContextManager, IAuthContext} from "../data";
export interface IMainViewOwnProps { someLabelFromExternalProps: string; }
export interface IMainViewExternalProps extends IAuthContext {}
export interface IMainViewProps extends IMainViewExternalProps, IMainViewOwnProps {}
@Provide(authContextManager)
@Consume<IAuthContext, IMainViewProps>(authContextManager)
export class MainView extends PureComponent<IMainViewProps> {
public render(): JSX.Element {
const {
someLabelFromExternalProps,
authState: {user, isAuthenticated},
authActions: {setUser, setUserAsync, changeAuthenticationStatus}
} = this.props;
const paddingStyle = { padding: "10px" };
return (
<div style={paddingStyle}>
<div> External prop value: '{ someLabelFromExternalProps }' </div>
<div style={paddingStyle}>
<span>USERNAME: </span> {user} <br/>
<span>AUTHENTICATED: </span> {isAuthenticated.toString()} <br/>
</div>
<div style={paddingStyle}>
<button onClick={changeAuthenticationStatus}>Change Authentication Status</button>
<button onClick={setUserAsync}>Randomize User Async</button>
<button onClick={() => setUser("user-" + Math.floor(Math.random() * 100))}>Randomize User</button>
</div>
</div>
);
}
}
Example build config.
import * as webpack from "webpack";
import * as path from "path";
const HtmlWebpackPlugin = require("html-webpack-plugin");
const mode = process.env.NODE_ENV;
const projectRoot = path.resolve(__dirname, "./");
export class WebpackConfig implements webpack.Configuration {
mode: "development" = "development";
resolve = {
extensions: [".ts", ".tsx", ".js", ".jsx"]
};
entry = [
path.resolve(projectRoot, "src/Application.tsx")
];
output = {
path: path.resolve(projectRoot, "target/"),
filename: "js/[name].bundle.js",
sourceMapFilename: "js/map/[name].bundle.map"
};
devtool: "source-map" = "source-map";
module = {
rules: [
{
test: /\.(ts|tsx)$/,
loader: "awesome-typescript-loader",
query: {
configFileName: path.resolve(projectRoot, "./tsconfig.json")
}
}
]
};
plugins = [
new HtmlWebpackPlugin({
inject: true,
filename: "index.html",
template: path.resolve(projectRoot, "src/index.html")
})
];
devServer = {
contentBase: "target/",
historyApiFallback: true,
compress: true,
port: 3000,
host: "0.0.0.0"
}
}
export default new WebpackConfig();
Pure JS example:
import * as React from "react";
import {PureComponent} from "react";
import {render} from "react-dom";
import {Consume, Provide, ReactContextManager} from "@redux-cbd/context";
export class AuthContext extends ReactContextManager {
changeAuthenticationStatus = () => {
this.state.authState = { ...this.state.authState, isAuthenticated: !this.state.authState.isAuthenticated };
this.update();
};
setUser = (user) => {
this.state.authState = { ...this.state.authState, user };
this.update();
};
setUserAsync = () => {
return new Promise((resolve) => {
setTimeout(() => {
this.state.authState = {...this.state.authState, user: "user-" + Math.floor(Math.random() * 10000)};
this.update();
resolve();
}, 3000)
});
};
context = {
authActions: {
changeAuthenticationStatus: this.changeAuthenticationStatus,
setUserAsync: this.setUserAsync,
setUser: this.setUser
},
authState: {
isAuthenticated: true,
user: "anonymous"
}
};
}
const authContext = new AuthContext();
@Provide(authContext)
@Consume(authContext)
export class MainView extends PureComponent {
render() {
const {
label,
authState: {user, isAuthenticated},
authActions: {setUser, setUserAsync, changeAuthenticationStatus}
} = this.props;
const paddingStyle = { padding: "10px" };
return (
<div style={paddingStyle}>
<div> External prop value: '{ label }' </div>
<div style={paddingStyle}>
<span>USERNAME: </span> {user} <br/>
<span>AUTHENTICATED: </span> {isAuthenticated.toString()} <br/>
</div>
<div style={paddingStyle}>
<button onClick={changeAuthenticationStatus}>Change Authentication Status</button>
<button onClick={setUserAsync}>Randomize User Async</button>
<button onClick={() => setUser("user-" + Math.floor(Math.random() * 100))}>Randomize User</button>
</div>
</div>
);
}
}
render(
<div>
<MainView label={ "First component." }/>
<MainView label={ "Second component." }/>
</div>,
document.getElementById("application-root")
);
Documentation:
Repository wiki includes docs and samples.
Proposals and contribution:
Feel free to contibute or mail me with questions/proposals/issues (Neloreck@gmail.com).
Full examples
Repository includes example project with commentaries: link.
My own 'redux-cbd' based project: link.
Library unit tests also include some different examples of cbd usage.
Licence
MIT