question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Alternative API proposals

See original GitHub issue

This API is taken from Redux <Provider>, <Connector>, @provide, @connect. Right now I don’t have examples in this repo but it matches what you’ve seen in Redux so far.

It’s the best we’ve got now, but I think we can do better!

Common pain points:

  • Not intuitive how way to separate smart and dumb components with <Connector>, @connect
  • You have to manually bind action creators with bindActionCreators helper which some don’t like
  • Too much nesting for small examples (<Provider>, <Connector> both need function children)

Let’s go wild here. Post your alternative API suggestions.

They should satisfy the following criteria:

  • Some component at the root must hold the store instance. (Akin to <Provider>)
  • It should be possible to connect to state no matter how deep in the tree
  • It should be possible to select the state you’re interested in with a select function
  • Smart / dumb components separation needs to be encouraged
  • There should be one obvious way to separate smart / dumb components
  • It should be obvious how to turn your functions into action creators
  • Smart components should probably be able to react to updates to the state in componentDidUpdate
  • Smart components’ select function needs to be able to take their props into account
  • Smart component should be able to do something before/after dumb component dispatches an action
  • We should have shouldComponentUpdate wherever we can

Issue Analytics

  • State:closed
  • Created 8 years ago
  • Reactions:2
  • Comments:79 (40 by maintainers)

github_iconTop GitHub Comments

3reactions
gaearoncommented, Jul 31, 2015

Normal arguments:

Vanilla form

connect(
  state => ({ state.counter }),
  dispatch => ({
    increment: () => dispatch(CounterActions.increment())
  })
)(Counter) 

wrapActionCreators sugar

connect({
  state => ({ state.counter }),
  wrapActionCreators(CounterActions)
})(Counter)

I want just the state

connect(
  state => ({ state.counter })
)(Counter) 

I want just some action creators

connect(
  null, // means "no need to subscribe at all"
  wrapActionCreators(CounterActions)
)(Counter) 

I want just the dispatch function

connect(
  null,
  dispatch => ({ dispatch })
)(Counter) 

I want to pass several action creator groups down

function wrapActionCreatorMap(map) {
  return dispatch => mapValues(map, actionCreators => wrapActionCreators(actionCreators)(dispatch));
}

connect(
  state => state.counter,
  wrapActionCreatorMap({
    counterActions: CounterActions,
    userActions: UserActions
  })
)(Counter)

I want to merge several action creator groups

connect(
  state => state.counter,
  wrapActionCreators(...CounterActions, ...UserActions)
)(Counter)

I want to pass actions down in a single object

function merge(counter, actions, props) {
  return { counter, actions, ...props };
}

connect(
  state => state.counter,
  wrapActionCreators(CounterActions),
  merge
)(Counter)

I want to use props for getting state and tweaking actions

function merge(counters, actions, props) {
  const { counterId, ...rest } = props;
  const { increment, decrement } = actions;
  return {
    counter: counters[counterId],
    increment: () => increment(counterId),
    decrement: () => decrement(counterId),
    ...rest
  };
}

connect(
  state => state.counters,
  wrapActionCreators(CounterActions),
  merge
)(Counter)
1reaction
faassencommented, Jul 13, 2015

I like the general direction in which this is going – it makes it possible to entirely keep any Redux related stuff out of plain React components, including the whole actions mechanism.

Getting props to tweak action creators is an important use case, I think, so it’s important it’s made easy. In hypermedia-based UIs you often pass URLs around as properties and then pass them into action creators Note that this is distinct from the parameterized action creator use case where you want to parameterize a whole bunch of related actions.

I’m not sure I fully understand the consequences of merge yet. Is the primary reason ‘merge’ is not the second argument (replacing the actions arg with a dispatch arg) for performance reasons or for usability reasons? If performance reasons, does this mean that any kind of parameterized action will degrade an application’s performance because props vary more? Action tweaking in merge creates new functions, which could potentially cause props to be different. But should merge be called at all if the state and props haven’t changed since the last time? Could merge be memoized?

merge is responsible for creating the entire prop object that goes into the underlying component. That makes it very flexible and I appreciate that, but I would like to explore approaches where the developer doesn’t have to worry about all that. I’d like to support something like this:

function tweak(counters, actions, props) {
  const { counterId } = props;
  const { increment, decrement } = actions;
  return {
    counter: counters[counterId],
    increment: () => increment(counterId),
    decrement: () => decrement(counterId),
  };
}

You could write a higher order function that does this:

function createMerge(func) {
   return (state, actions, props) => {
        const tweaked = func(state, actions, props);
        return { ...props, ...tweaked };
  };
}

const merge = createMerge(tweak);

Are performance optimization opportunities lost this way?

From the readability perspective I have a slight preference for named parameters. But named parameters have the drawback that is supports some uses cases (like binding actions without state) I understand are less than optimal without signalling the developer (by requiring a null arg) that they are taking a suboptimal approach. Named parameters have the benefit of extensibility: it would make it easy to add a tweak parameter. But I think that’s the kind of extensibility you don’t want at this level. So I can see reasons for using normal arguments in this case.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Top 10 Fresh Proposals Alternatives 2022 - G2
Top 10 Alternatives to Fresh Proposals · Proposify · PandaDoc · Qwilr · Conga Composer · GetAccept · RFPIO · DocSend · DealHub.io....
Read more >
15 Proposify Alternatives to Choose From - PandaDoc
15 Proposify alternatives. 1. PandaDoc; 2. Qwilr; 3. Bidsketch; 4. QuoteWerks; 5. Better Proposals; 6. Proposable; 7. Qvidian; 8. Nusii; 9.
Read more >
API Urges SEC to Consider Alternative Approaches to Climate ...
In the comments, API states that the proposed rule is unlikely to achieve the SEC's goal of providing more consistent, comparable, and reliable ......
Read more >
Proposify Alternative | Nusii Proposals
Looking for a better alternative to Proposify for your proposals? Nusii is proposal software designed specifically for creative businesses.
Read more >
A Proposal for an Alternative Design for Hooks - paulgray.net
If we realized an alternative API based on functional programming patterns, we could have hook functions that: Have meaningful signatures. Have ...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Hashnode Post

No results found