Skip to content

Prefixes/Namespacing proposed syntax #159

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

Closed
Strandedpirate opened this issue Nov 12, 2016 · 6 comments
Closed

Prefixes/Namespacing proposed syntax #159

Strandedpirate opened this issue Nov 12, 2016 · 6 comments
Assignees

Comments

@Strandedpirate
Copy link

Strandedpirate commented Nov 12, 2016

For namespacing, which I would like to see, how about supporting this kind of syntax? This actually reduces boilerplate in the destructing assignment for all 2'nd level action creators and prevents having to keep keys and their destructed names in sync.

const {
  rootLevelAction,
   // no keys below products or orders must be kept in sync here. yeah!!!
  products,
  orders,
} = createActions({
	rootLevelAction: () => ({}),
	products: { // this key used for the namespace prefix
	  list: (query) => ({ query }),
	  addToCart: (quantity, productId) => ({ quantity, productId }),
	},
	orders: { // this key used for the namespace prefix
	  placeOrder: (cartId) => ({ cartId }),
	  getOrder: (orderId) => ({ orderId }),
	}
});

Example usage:

dispatch(rootLevelAction());
dispatch(products.list('Star Wars'));
dispatch(products.addToCart(1, 45243));
dispatch(orders.placeOrder(7348));
dispatch(orders.getOrder(45));

Destructures to the following:

rootLevelAction: function() {
	return {
		type: 'rootLevelAction',
		payload: { }
	};
},
products:{
	type: 'products',
	list: function(query) {
		return {
			type: 'products/list', // boom, namespaced to reduce collisions
			payload: { query }
		};
	},
	addToCart: function(quantity, productId) {
		return {
			type: 'products/addToCart',
			payload: { quantity, productId }
		};
	}
},
orders:{
	type: 'orders',
	placeOrder: function(cartId) {
		return {
			type: 'orders/placeOrder',
			payload: { cartId }
		};
	},
	getOrder: function(orderId) {
		return {
			type: 'orders/getOrder',
			payload: { orderId }
		};
	}
}

Supporting an unlimited level of literal nesting would be awesome and allow for richly namespaced action creators that reduce the chance of collisions.

@Strandedpirate Strandedpirate changed the title Prefixes/Namecpacing proposed syntax Prefixes/Namespacing proposed syntax Nov 12, 2016
@yangmillstheory yangmillstheory self-assigned this Nov 12, 2016
@yangmillstheory
Copy link
Contributor

yangmillstheory commented Nov 13, 2016

I would prefer that this be kept out of the library; but that doesn't mean we can't come up with a reasonable solution.

If we can re-implement a smarter camel-casing function (see #135), we can actually push the rest of the solution out to userland.

const {createActions} = require('redux-actions')

// can genericize to leaves of any type, should be pulled from a utility module
const flatten = (
  target,
  delimiter,
  flattened = {},
  path = ''
) => {
  function getNextPath(key) {
    return path ? `${path}${delimiter}${key}` : key
  }
  for (const key in target) {
    const nextPath = getNextPath(key)
    if (typeof target[key] === 'function') {
      flattened[nextPath] = target[key]
      continue
    }
    flatten(target[key], delimiter, flattened, nextPath)
  }
  return flattened
}

const actions = flatten({
  orders: {
    getOrder: orderId => ({orderId}),
    placeOrder: cartId => ({cartId}),
  },
  products: {
    addToCart: (productId, quantity) => ({productId, quantity}),
    list: query => ({query}),
  },
  rootLevelAction: () => ({}),
  },
  '/'
)

console.log(actions)
console.log(createActions(actions))
[~/code/private/js-standard]  (master|%=)
$ node test.js
{ 'orders/getOrder': [Function: getOrder],
  'orders/placeOrder': [Function: placeOrder],
  'products/addToCart': [Function: addToCart],
  'products/list': [Function: list],
  rootLevelAction: [Function: rootLevelAction] }
{ ordersGetOrder: { [Function: actionCreator] toString: [Function] },
  ordersPlaceOrder: { [Function: actionCreator] toString: [Function] },
  productsAddToCart: { [Function: actionCreator] toString: [Function] },
  productsList: { [Function: actionCreator] toString: [Function] },
  rootLevelAction: { [Function: actionCreator] toString: [Function] } }

Unfortunately our camel-casing function doesn't respect special delimiters, like /. I'd be happy to take care of this; then you'd be responsible for implementing the generic flattening (feel free to copy the code above).

@yangmillstheory
Copy link
Contributor

yangmillstheory commented Nov 20, 2016

I've released redux-nested-actions, but it won't work until #166 gets merged. This would let you namespace and structure your actions hierarchy to whatever depth you want.

@renato
Copy link

renato commented Feb 20, 2017

I'm using a custom solution that works for me, but it would be better if something "official" was supported. Are you going to support something like this or userland custom solutions are good enough?

@yangmillstheory
Copy link
Contributor

I'd like to get this into core; userland code like what I linked to above is a bit awkward. I'll submit a PR this weekend.

@yangmillstheory
Copy link
Contributor

I'm proposing something like https://github.com/yangmillstheory/redux-nested-actions/blob/master/src/index.test.js; planning on getting this in tomorrow.

@renato
Copy link

renato commented Mar 5, 2017

Thanks @yangmillstheory, it's working great.

I had to change some dumb actions that were in the string form (second createActions arg) to the object form but, after all, I think it was confusing to have these mixed configs.

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

No branches or pull requests

3 participants