Neanderthals Programming Machines

    @redux-cbd/context

    1.1.1 • Public • Published

    🗻 @redux-cbd/context

    npm version language-ts
    start with wiki license
    npm downloads HitCount


    @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

    @Annotations Utils
    @Consume ReactContextManager
    @Provide -

    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 {
    
      /*
       * { ...{} as IConnectedComponentExternalProps } is the trick for correct types handling.
       * Actually, connected component is different from the one we exported with 'export class'.
       * We should use default export with separate props cast or make such mock trick.
       * (I prefer second style with single class declaration and DIRECTLY NAMED imports, which are better).
       */
      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> {
    
      private static ASYNC_USER_CHANGE_DELAY: number = 3000;
    
      // Default context state.
      protected readonly context: IAuthContext = {
        // Some kind of handlers.
        authActions: {
          changeAuthenticationStatus: this.changeAuthenticationStatus,
          setUserAsync: this.setUserAsync,
          setUser: this.setUser
        },
        // Provided storage.
        authState: {
          isAuthenticated: true,
          user: "anonymous"
        }
      };
    
      @Bind()
      public changeAuthenticationStatus(): void {
        this.context.authState.isAuthenticated = !this.context.authState.isAuthenticated;
        this.update();
      }
    
      @Bind()
      public setUser(user: string): void {
        this.context.authState.user = user;
        this.update();
      }
    
      @Bind()
      public setUserAsync(): Promise<void> {
        return new Promise((resolve) => {
          setTimeout(() => {
            this.context.authState.user = "user-" + Math.floor(Math.random() * 10000);
            this.update();
    
            resolve();
          }, AuthContextManager.ASYNC_USER_CHANGE_DELAY)
        });
      }
    
    }
    Connected component.

    import * as React from "react";
    import {PureComponent} from "react";
    import {Consume, Provide} from "@redux-cbd/context";
    
    // Store related things.
    
    import {authContextManager, IAuthContext} from "../data";
    
    // Props typing.
    
    export interface IMainViewOwnProps { someLabelFromExternalProps: string; }
    
    export interface IMainViewExternalProps extends IAuthContext {}
    
    export interface IMainViewProps extends IMainViewExternalProps, IMainViewOwnProps {}
    
    // Component related.
    
    @Provide(authContextManager)
    @Consume(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, "./");
    
    // For development purposes only.
    // Extend and rewrite it properly with webpack documentation.
    // Use proper config for production builds.
    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";
    
      // Add the loader for .ts files.
      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";
    
    // Data store.
    
    export class AuthContext extends ReactContextManager {
    
      changeAuthenticationStatus = () => {
        this.state.authState.isAuthenticated = !this.state.authState.isAuthenticated;
        this.update();
      };
    
      setUser = (user) => {
        this.state.authState.user = user;
        this.update();
      };
    
      setUserAsync = () => {
        return new Promise((resolve) => {
          setTimeout(() => {
            this.state.authState.user = "user-" + Math.floor(Math.random() * 10000);
            this.update();
            resolve();
          }, 3000)
        });
      };
    
      // Wrap your actions and state separately to avoid naming collisions.
      context = {
        authActions: {
          changeAuthenticationStatus: this.changeAuthenticationStatus,
          setUserAsync: this.setUserAsync,
          setUser: this.setUser
        },
        authState: {
          isAuthenticated: true,
          user: "anonymous"
        }
      };
    
    }
    
    const authContext = new AuthContext();
    
    // View.
    
    /*
     * Single provide-consume component.
     * Actually, only one module component (for example, router) should provide context.
     * All you need - inject props by consuming.
     */
    @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 into DOM.
    
    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

    Install

    npm i @redux-cbd/context

    DownloadsWeekly Downloads

    14

    Version

    1.1.1

    License

    MIT

    Unpacked Size

    24.6 kB

    Total Files

    15

    Last publish

    Collaborators

    • neloreck