• Stars
    star
    116
  • Rank 303,894 (Top 6 %)
  • Language
    TypeScript
  • License
    MIT License
  • Created about 9 years ago
  • Updated over 7 years ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Seed for building React app using Typescript and Webpack build using FLUXless architecture

React Typescript Webpack FLUXless Todo Example Build Status

Seed for building React apps using FLUXless architecture, Typescript and Webpack build

Check out the Demo

Features

This is a simple Todos application with some sweet extra features like authentication (using Auth0) and persistence (separate node.js backend application - check out the gihub repository of todos-server)

  • FLUXless architecture - simple one way data flow (just components, services, models)
  • guest mode - local storage persistence
  • persistence - separate node.js backend application for authenticated users
  • authentication - Auth0 3rd party API with Google+ social login
  • material design - material-ui, react-bootstrap, material bootswatch theme
  • continuous deployment - travis ci build + deployment to gh-pages branch fo the repository (GitHub Pages)
  • webpack build - with react hot loader

How to run the project

  1. npm i - install npm dependencies
  2. npm start - run webpack build in DEV mode, open http://localhost:8081 in browser

Other build targets

  • npm run build - run build and store artifacts in build folder
  • npm run dist - run production build and stores artifacts in dist folder
  • npm run ci - build for Travis CI
  • npm run test - run lint & test

Preview

Components

Disclaimer: I think Flux architecture and it's multiple implementations are great idea but it is always good to understand the bigger picture and related trade-offs...

Motivation for FLUXless architecture

In software development, we should strive to attain deeper understanding of concepts instead of falling for the ever-changing HypeOfTheMonthYear. I was interested and a bit skeptical about the latest Flux hype and all the different libraries it spawned during relatively short period of time. Researching the topic brought fruit pretty quickly. In my opinion, this thread on reddit contains lot of insight into the situation.

TLDR; MVC done incorrectly doesn't scale so we replaced it with MVC done correctly and gave it a cooler name.

or

As far as I can tell (and as others have said) - FB seems to have missed the boat here. Their FLUX diagram is what I understood proper MVC to be...

These and many other similar comments are hinting that Flux may be just a specific implementation of MVC and that the main point (or constraint) is that the data must ALWAYS flow in one direction. Flux implementations usually achieve that by decoupling of all logic calls (in Actions) by event bus (Dispatcher) from their execution (in Stores). As it turned out, one way data flow is also easily achievable by using more familiar architecture with React components, services and models (check todo.container.ts, todo.service.ts, todo.model.ts to get an idea).

Architecture

The main concept at the core of all Flux implementations is that the data must always flow in one direction. This is a worthy cause and it brings a lot of benefits to the table during development and maintenance of projects. With such an architecture project state becomes predictable, easier to reason about and debug.

Event bus vs explicit calls

Flux decouples logic by implementing event bus with the Dispatcher being responsible for dispatching Action generated events to all the Stores. As everything, events too come with a trade-off. They enforce decoupling of application logic by their very nature. The cost of that is that it is usually much harder to track and debug event-heavy code. Yes you can store complete event history to see what happened in your application but you lose ability to easily comprehend scope of all the logic that will be executed as a result of producing single event. Another problem is assuring that the dependent operations happen in correct order (waitsFor from original Facebook's Flux example'). It might be matter of subjective preference but if you need to orchestrate complex business flows through various domains, nothing beats explicit calls.

Architecture

UI

React components

In this example we are using two types of React components with different set of responsibilities.

Container components

Container components are handling following tasks:

  • hold current (rendered) application state
  • register model change listeners to get notified on model data change
  • retrieve actual data on model change
  • pass state to children components through their props
  • implement calls to domain & application services (and pass them to children)

Template of container components consist purely of other React components (no own layout or functionality).

export default class TodoContainer extends React.Component<{}, {}> {

    constructor(props) {
        super(props);
        this.state = this._buildState();
    }

    // register model data change listeners
    componentDidMount() { TodoModel.observable.addListener(this._onModelUpdate.bind(this)); }
    componentWillUnmount() { TodoModel.observable.removeListener(this._onModelUpdate.bind(this)); }

    // handle model data change
    _onModelUpdate() {
        this.setState(this._buildState());
    }

    // helper function for retrieving state on model data change
    _buildState() {
        return {
            todos: TodoModel.getTodos()
        }
    }

    addTodo(description: string) { /* ... */ }

    // simplified for brevity

    render() {
        return(
            <TodoComponent todos={this.state.todos} addTodo={this.addTodo.bind(this)} />
        );
    }

}

Simple components

Simple components receive all their data and functionality through props (from parent component). They can implement their own local state and logic for handling of internal UI interactions but all mutations to the application state stored in models can only be achieved by executing functions received from parent through props (which are in turn calling domain and application services).

Logic

Domain separation

As applications grow larger it is usually a good idea to split functionality into multiple folders (packages) by their respective concern. In the perfect world these concerns would be perfectly orthogonal so we didn't have to implement any cross domain orchestration or cross-cutting concerns. Unfortunately, that's rarely the case and we usually have to deal with cross-domain coordination when implementing our business flows.

Application services

Application services (~Actions) are used to implement cross-domain orchestration. They are the only type of service which are allowed to import services from other domain packages. They only execute functionality of imported domain services and contain no business logic on their own.

(Domain) Services

Services (~Actions / Stores) are used to implement domain specific business and infrastructure logic. Services of particular domain can import only other services belonging to that domain. All inter-domain orchestration must be implemented using application services. Logic can be separated into multiple services based on concern (eg: business logic, persistence, ...).

Models

Models (~Stores) are responsible for holding app state during it's runtime. They implement observe/notify design pattern so that all interested container components can use model's addListener method to register callback to be notified when the model data change. This implementation enables one way data flow. Model has full control of the (possibly custom) notification behaviour, while component knows what kind of data it needs to retrieve from model after being notified.

All get data functions of the model create copy of the retrieved data so that they prevent direct mutation of model's data through shared reference. Also, while it is theoretically possible for component to directly call other model's methods, as guideline only listener and get methods are allowed.

Contributing

Don't hesitate to fork / submit PR with enhancements if you found this example useful.

TODO

  • tslint
  • unit tests
  • integration tests
  • add notifications / alerts for operation's outcomes
  • cleanup of styling (select just one component library)
  • add form validation messages

More Repositories

1

angular-ngrx-material-starter

Angular, NgRx, Angular CLI & Angular Material Starter Project
TypeScript
2,832
star
2

angular-js-es6-testing-example

Enhanced testing of Angular JS 1.X applications using ES6 modules
JavaScript
171
star
3

ngx-model

Angular Model. Simple state management with minimalistic API, one way data flow, multiple model support and immutable data exposed as RxJS Observable.
TypeScript
133
star
4

component-pattern-for-angular-js-1-x

Example of implementation of Component pattern for Angular JS 1.X using ES6 & Webpack
JavaScript
70
star
5

angular-architecture-example

TypeScript
68
star
6

medium-enhanced-stats

Google Chrome Extension for enhanced Medium stats! Get insight into total view count with new table summary row...
JavaScript
67
star
7

angular-library-architecture-example

Angular Library Architecture Example
TypeScript
40
star
8

angular-model-pattern-example

Model pattern for Angular (2, 4, ...), manage and share your state with simple services using RxJS Subjects and Observables
HTML
36
star
9

ngx-model-hacker-news-example

Example repository with Hacker News implementation using Angular, Angular Material & ngx-model
TypeScript
27
star
10

releasebot

TypeScript
18
star
11

angular-lazy-lib-demo

How to lazy load modules from Angular libraries example
TypeScript
17
star
12

workshop-angular-schematics

TypeScript
13
star
13

grunt-ngsrc

Find and add your Angular.js source files into index.html automatically
JavaScript
11
star
14

angular-monorepo-enterprise-starter

Angular Monorepo Enterprise Starter
TypeScript
10
star
15

jasmine-async-sugar

Simple drop-in syntax sugar for Jasmine 2.X test framework to enhance testing of async (promise) functionality to be used with Angular 1.X
JavaScript
8
star
16

meetup-angular-material-themes-example

Angular Material Themes Code Example for Angular Meetup Zurich 21. 8. 2017
TypeScript
8
star
17

node-babel-es6-example

Use ES6 module syntax in node.js with minimalized Babel influence (because node.js already supports most ES6 features)
JavaScript
5
star
18

tomastrajan-com

TypeScript
4
star
19

ngrx-test

WIP
TypeScript
2
star
20

webpack-seed

Fully featured webpack build
JavaScript
2
star
21

angular-bootstrap-example

Minimalistic Angular 6 Bootstrap 4 integration example
TypeScript
2
star
22

ngconsultant

ng-consultant website
TypeScript
2
star
23

Quado

Android arkanoid (breakout) type game
Java
2
star
24

angular-rxjs-websocket-example

TypeScript
2
star
25

complete-angular2-seed

Feature complete seed for Angular 2.0 applications with Typescript, Webpack build and focus on code style, testing and production ready packaging
TypeScript
1
star
26

fintech-example

TypeScript
1
star
27

ngx-model-example

Simple example project of using ngx-model in Angular application
TypeScript
1
star
28

grunt-npm-install-all

Run npm install in all matching directories with package.json file (exclude package.json files in already installed node_modules directories)
JavaScript
1
star
29

ultimate-es6-migration-guide-modules

Ultimate ES6 / ES2015 migration guide - Modules - forward backward compatibility & caveats
JavaScript
1
star
30

avatarjs-hapijs-seed

Seed project for Avatar.js (running node.js in JVM) & hapi.js (node.js web app framework)
Batchfile
1
star
31

http-request-cancelation-example

TypeScript
1
star
32

Quado-server

Score sharing backend
JavaScript
1
star
33

angular2-typescript-webpack

Angular 2 Typescript Webpack starter project
TypeScript
1
star
34

angular-signals-effect

Created with StackBlitz ⚑️
TypeScript
1
star
35

angular-elements-cd-example

TypeScript
1
star