Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Redux Injector (Enables bindings between redux and dojo 2 widget-core) #2

Merged
merged 6 commits into from
Sep 13, 2017

Conversation

agubler
Copy link
Member

@agubler agubler commented Aug 16, 2017

Type: feature

The following has been addressed in the PR:

  • There is a related issue
  • All code matches the style guide
  • Unit or Functional tests are included in the PR

Description:

Adds a redux injector that can used to bind a redux store and dojo 2 widgets using the Container pattern.

Define an injector in the registry and then use Container to inject the store.

Example Usage:

import { WidgetBase } from '@dojo/widget-core/WidgetBase';
import { registry, v } from '@dojo/widget-core/d';
import { Injector } from '@dojo/widget-core/Injector';
import { Container } from '@dojo/widget-core/Container';
import { ProjectorMixin } from '@dojo/widget-core/mixins/Projector';
import { ReduxInjector } from '@dojo/interop/redux';
import { createStore } from 'redux';

// the reducer for the example state
function reducer(state: any = { counter: 0 }, { type, payload }: any) {
	switch (type) {
		case 'INCREMENT_COUNTER':
			return { counter: state.counter + 1 };
		case 'DECREMENT_COUNTER':
			return { counter: state.counter - 1 };
		default:
			return state;
	}
}

// create the redux store with reducers
const store = createStore(reducer);

// Defines the injector in the registry
registry.define('redux-store', Injector(ReduxInjector, store));

// properties for the example widget
interface ReduxExampleProperties {
	counter: number;
	incrementCounter: () => void;
	decrementCounter: () => void;
}

// example widget
class ReduxExample extends WidgetBase<ReduxExampleProperties> {
	decrement() {
		this.properties.decrementCounter();
	}

	increment() {
		this.properties.incrementCounter();
	}

	render() {
		return v('span', [
			v('button', { onclick: this.decrement, disabled: this.properties.counter === 0 }, [ 'decrement' ]),
			v('span', [ ` Counter ${this.properties.counter} ` ]),
			v('button', { onclick: this.increment }, [ 'increment' ])
		]);
	}
}

// binding the redux injector and the widget together, specifying a function that injects attributes
// from the store into the widget as properties
const ReduxExampleContainer = Container(ReduxExample, 'redux-store', { getProperties: (store: Store<any>, properties: any) => {
	const state = store.getState();

	function incrementCounter() {
		store.dispatch({ type: 'INCREMENT_COUNTER' });
	}

	function decrementCounter() {
		store.dispatch({ type: 'DECREMENT_COUNTER' });
	}
	return {
		counter: state.counter,
		incrementCounter,
		decrementCounter
	};
}});

// append the widget
const Projector = ProjectorMixin(ReduxExampleContainer);
const projector = new Projector();
projector.append();

Resolves #1

@agubler
Copy link
Member Author

agubler commented Aug 16, 2017

Needs tests

@codecov
Copy link

codecov bot commented Aug 18, 2017

Codecov Report

❗ No coverage uploaded for pull request base (master@24faa62). Click here to learn what that means.
The diff coverage is 90%.

Impacted file tree graph

@@          Coverage Diff           @@
##             master    #2   +/-   ##
======================================
  Coverage          ?   90%           
======================================
  Files             ?     1           
  Lines             ?    10           
  Branches          ?     1           
======================================
  Hits              ?     9           
  Misses            ?     0           
  Partials          ?     1
Impacted Files Coverage Δ
src/redux/ReduxInjector.ts 90% <90%> (ø)

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 24faa62...4ba2526. Read the comment docs.

Copy link
Member

@kitsonk kitsonk left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just the thought on how dependencies are managed for interop

package.json Outdated
"grunt": "~1.0.1",
"grunt-dojo2": "latest",
"intern": "^3.4.6",
"typescript": "~2.4.2"
},
"dependencies": {
"redux": "^3.7.2"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So, anyone using interop is going to have to pull in redux? Would it make sense to just have it as a dev dependency and then the end user chooses what sort of dependencies/parts of interop they are using?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah perhaps that is better.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thinking about this, perhaps they do have to pull in redux... because otherwise the more likely mistake will be they don't install redux at all!

After all it will only get included in the bundle if they actually use it.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess I can see both sides of it... but, it means that this will grow and grow and grow in dependencies whenever it is installed as we increase the capabilities of the package. I wasn't planning on adding dojo and dijit as dependencies when we introduce the DijitWrapper. It would just seem to me that it would be "bring your own production libraries" sort of thoughts, with the code here as loosely coupled as possible.

After all, the build will error if they don't install it. 😉

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about a peer dependency? seems like that would be the most appropriate... I think you'd actually be okay to add dojo and dijit too :)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Gotta ❤️ peerDependency... only thing is if I want to use DijitWrapper then react wouldn't be a dependency at all. There is no easy way to deal with that, except for maybe optionalDependencies?

@agubler agubler merged commit bce86c5 into dojo:master Sep 13, 2017
@dylans dylans added this to the 2017.09 milestone Sep 26, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants