Coder Social home page Coder Social logo

redux-ui's Introduction

Circle CI

redux-ui: ui state without profanity

Think of redux-ui as block-level scoping for UI state. In this example each block-scope represents a component, and each variable represents a UI state key:

{
  // Everything inside this scope has access to filter and tags. This is our root UI component.
  let filter = '';
  let tags = [];

  // Imagine the following scopes are a list of to-do tasks:
  {
    // Everything inside this scope has access to isSelected - plus all parent variables.
    let isSelected = true
  }
  {
    // This also has isSelected inside its scope and access to parent variables, but
    // isSelected is in a separate scope and can be manipulated independently from other
    // siblings.
    let isSelected = false
  }
}

Wrap your root component with the redux-ui @ui() decorator. It's given a new scope for temporary UI variables which:

  • are automatically bound to this.props.ui
  • are automatically passed any child component wrapped with the @ui() decorator
  • will be automatically reset on componentWillUnmount (preventable via options)
  • can be reset manually via a prop
  • are updatable by any child component within the @ui() decorator

This is powerful. Each component is reusable and can still affect UI state for parent components.

Setup

Step 1: Add the redux-ui reducer to your reducers under the ui key:

import { reducer as uiReducer } from 'redux-ui'
// ...
combineReducers({ ...yourReducers, ui: uiReducer })

Step 2: In each 'scene' or parent component add the UI decorator with the key in which to save all state:

import ui from 'redux-ui';

@ui({
  state: {
    yourVars: 'withDefaults',
    filters: []
  }
})
class YourComponent extends React.Component {
}

Step 3: In each child component use the basic @ui() decorator; it will automatically read and write UI state to the parent component's UI key.

You can also define variables in child components. If your child component has variables named the same as a parent component think of block scoping: everything within your child component down will read from the child's scope, but the parent will use the parent's UI variable.

Usage

The @ui decorator injects four props into your components:

  1. uiKey: The key passed to the decorator from the decorator (eg. 'some-decorator' with @ui('some-decorator')
  2. ui: The UI state for the component's uiKey
  3. updateUI: A function accepting either a name/value pair or object which updates state within uiKey
  4. resetUI: A function which resets the state within uiKey to its default

The decorator will set any default state specified (see below). On componentWillUnmount the entire state in uiKey will be set to undefined. You can also blow away state by calling resetUI (for example, on router changes).

Decorator API

The decorator takes an object of options:

@ui({
  // optional key which is used to determine the UI path in which state will
  // be stored. if omitted this is randomly generated.
  key: 'some-name',
  // optional persist, defaults to false. if set to true persist will keep UI
  // state for this component after it unmounts. if set to false the UI state will
  // be deleted and recreated when the component remounts
  persist: true,
  // **required**: UI state for the component
  state: {
    uiVar1: '',
    // You can set default UI state based on the component's props and the
    // global store's state.
    uiVar2: (props, state) => state.router.location.query.searchTerm
  },
  // customReducer: you can handle the UI state for this component's scope by dispatching actions
  reducer: (state, action) => {
    // state represents *only* the UI state for this component's scope - not any children
    switch(action.type) {
      case '@@reduxReactRouter/routerDidChange':
        if (action.payload.location.query.extra_filters) {
          return state.set('extraFilters', true);
        }
      }
      return state;
    }
  },
  // optional mergeProps passed to react-redux' @connect
  mergeProps: () => ({}),
  // optional `options` passed to react-redux @connect
  options: {}
})

Non-decorator API

You can use redux-ui without using an ES7 decorator like so:

import ui from 'redux-ui';
// or ui = require('redux-ui').default;

class SomeComponent extends Component {
}

SomeComponentWithUI = ui({ key: 'some-name', state: { ... }})(SomeComponent);
key: string, defaults to random characters

The name of the key used in the UI reducer under which we store all state. Allows you to create selectors in reselect with known paths, and allows setting persist below.

If this is not specified it will be autogenerated based on the component name suffixed with a random hex code. Components using the same key will share the same UI context, so don't supply a name to a list of components (generated in a loop) if they need their own UI state.

persist: bool, defaults to false

Set to true if the UI state for this component should persist after componentWillUnmount. You must also explicitly define a key for this component, otherwise the component will randomize the key and load new UI state on instantiation.

Note: All parent UI components also need to set this to true for this to take effect. Think of block-level scoping again โ€” if a parent scope quits all child scopes are also out of context.

state: object

All UI variables need to be explicitly defined in the state object. This allows us to determine which scope a variable belongs to, as scope is inherited in the component tree. Think of this as using let inside your block scopes.

Examples

import ui from 'redux-ui';

// Component A gets its own context with the default UI state below.
// `this.props.ui` will contain this state map.
@ui({
  state: {
    // use the filter query parma via redux-router as the default
    filter: (props, state) => state.router.location.query.filter,
    isFormVisible: true,
    isBackgroundRed: false
  }
})
class A extends Component {
  render() {
    return (
      <div>
        // This will render '{ "filter": '', isFormVisible: true, isBackgroundRed: false }'
        <pre><code>{ this.props.ui }</code></pre>

        // Render child B
        <B />
      </div>
    );
  }
}

// B inherits context from A and adds its own context.
// This means that this.props.ui still contains A's state map.
@ui()
class B extends Component {
  render() {
    return <C />;
  }
}

// C inherits context from its parent B. This works recursively,
// therefore C's `this.props.ui` has the state map from `A` **plus**
// `someChildProp`.
//
// Setting variables within C updates within the context of A; all UI
// components connected to this UI key will receive the new props.
@ui({
  state: {
    someChildProp: 'foo'
  }
})
class C extends Component {
  render() {
    return (
      <div>
        <p>I have my own UI state C and inherit UI state from B and A</p>
        <p>If I define variables which collide with B or A mine will
        be used, as it is the most specific context.</p>
    );
  }
}

Aims

UI state:

  1. Should be global
  2. Should be easily managed from each component via an action
  3. Should be easy to reset (manually and when unmounting)

All of these goals should be easy to achieve.


MIT license.

Written by Franklin Ta and Tony Holdstock-Brown.

redux-ui's People

Contributors

ignatiusreza avatar jdstep avatar kurtfunai avatar rivertam avatar tonyhb avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

redux-ui's Issues

Sending state across scenes?

Let's say we have two scenes A and B.

When user clicks a button on A they are taken to B with certain UI state already in effect.
In A you could perform updateUI with the key of B, but then defaults are not set when mounting B.

Let's also presume that using routing is out of scope.

What would be the recommended method?

compatibility with redux-immutablejs

Hi, I am using the combineReducers from redux-immutablejs, which always passes immutablejs object as state whereas redux-ui is expecting plain javascript object. I made a patch to make it work with redux-immutablejs and wondering if you are interested in.

enhancement: allow key to be a function

I have a generic list component and I'd like to use redux-ui to store it's state (selection, scroll state). If the 'key' prop was a function then I could keep the state for different instantiations of the control separate.

To be clear, this would be a function accepting props and state, just like the state initializers

UPDATE_UI_STATE vs MASS_UPDATE_UI_STATE and child components

I have a component that has this ui state property:

dialogOpen: false

I am trying to change it to this because I have several dialogs I want to track state of (where XXX is identifier of a dialog):

dialog: { open: false, ...other props }

I use updateUI('dialogOpen', true) and the child component sees changed state and will display itself. When updateUI('dialogOpen',false) is called the child component sees the change and hides itself.

But, when I switch to the second state the child component is not updated when I call:
updateUI( {dialog: merge(ui.dialog, {open: true} ) } )
)

The state is updated correctly as I can see it in the devTool monitor and can watch the action update the state correctly. But the child component is not notified/updated like in the first example.

I see that an UPDATE_UI_STATE action is sent in the first case when a string/value pair is passed to updateUI() but a MASS_UPDATE_UI_STATE is sent when passing an object to the updateUI().

My parent component state looks like this:
@ui({ key: 'client', persist: true, state: { activeTab: "contactLog", dialogOpen: false, dialog: { open: false, initValues: {}, values: {} }, ........
and my child component state (dumb and not connected) who reads the ui.state and sets up its ui according to values contained in the ui state....
@ui({ state: { buttons: { cancel: {id: "cancel", label: "Cancel"}, submit: {id: "submit", label: "Submit"}, } } })

How can I get the same behavior when passing an object to updateUI() ? Or how can I work around this difference?

Expose uiPath

If people are using thunks, or sagas then they will need to be able to update the UI from outside of the component. It would be nice to be able to send the uiPath to allow this.

Thoughts?

How to use it with an already connected component

I can't use the decorator way so I have to use the HOC approach.
I wonder if the store listeners get duplicated if I do:

export default connect(state => state.account)(ui()(Login))

Or whats the correct way to do that?

Using a decorator gives me:

Invariant Violation: Could not find "store" in either the context or props of "Connect(UI)". Either wrap the root component in a <Provider>, or explicitly pass "store" as a prop to "Connect(UI)".

@ui("login")
class Login {
}
export default connect(state => state.account, { login, loginSuccess })(Login)

I'd have hoped the component does not directly connect to the store but instead uses the default redux way to communicate with the store?

persist ui state

I would like to save off the ui state to storage and use that to init the state the next time the app starts up. Any suggestions on how to hook that in?

inject less props instead only one object

Props can clutter up pretty fast. The redux-ui decorator adds 4 of them. Since the lib is young I propose a breaking change and inject only one additional prop called ui. It contains the 2 properties key and state and the 2 update functions.

What u think?

Should we recalculate UI state when props change?

If your UI state depends on props:

@ui({
  state: {
    name: (props) => props.somethingFromAync
  }
})

We'll calculate the default UI on mount and never recalculate when the async call fetches.

Should we?

Pros

  1. It alleviates async functionality

Cons
2. You might be overriding explicitly set UI state from a user's interaction. This is bad.

Initial thoughts are that if this is an async request, you probably want to defer rendering the component with UI state until that request has finished.

Avoid binding in render

The render code in ui.js uses the binding operator to pass updateUI and resetUI to the underlying component. This creates new functions at each render pass since behind the scenes it is compiled to this.updateUI.bind(this) and this.resetUI.bind(this) leading to 2 issues:

  1. It cancels out shallowEqual/pure render mixin from any subcomponents they are passed to as props
  2. It needlesly creates new functions at each render pass.

Question: How would you recommend updating the UI from side effects such as sagas?

Let's say I have a saga whereby every time the url changes I want some part of my UI to update, for example a modal to close.

But if the modal UI hasn't rendered yet it obviously doesn't exist in the reducer (even if it isn't persistent). Therefore when it does finally mount the initial values will not be called.

So my question is, how would you recommend updating the UI from side effects such as sagas?

Uncaught Error: Your custom UI reducer at path X must return some state

I have two components that are nested Issues -> IssueCard. They each have their own customer reducers defined. When I unmount them - I get this error on the IssueCard path for the custom reducer.

The problem seems to be in action-reducer.js line ~144
var newState = func(mut.getIn(path), action);
if (newState === undefined) {
throw new Error('Your custom UI reducer at path ' + path.join('.') + ' must return some state');
}

The parent Issues gets unmounted this seems to wipe out the UI state for the child. Then it runs a second UI_UMOUNT_UI_STATE - it tries to run the custom reducer on a IssueCard (The state is undefined) and it returns undefined so the error trips.

This seems corrected by confirming that the existing state isn't already undefined before complaining:
if (newState === undefined && mut.getIn(path) !== undefined) {
throw new Error('Your custom UI reducer at path ' + path.join('.') + ' must return some state');
}

Using a non-decorator syntax

Currently using this in a hybrid es6 and coffeescript app where everything is slowly being ported to es6/babel. Unfortunately I need to use redux-ui on some of the coffeescript files, any tips on how I should approach this?

Omitting state interpolation when persist isn't set

First of all - good job guys! I really like idea of this package!

I've found some disturbing bug (feature?): when the persist option isn't set sometimes state variables with functional value are not interpolated. Here is the example:

import React, { Component, PropTypes } from 'react';
import ui from 'redux-ui';

@ui({
  key: 'some-name',
  // persist: true,
  state: {
    uiVar1: () => 1
  }
}) export default class TestUIComponent extends Component {
  static propTypes = {
    ui: PropTypes.object.isRequired,
  };

  render() {
    const { ui: { uiVar1 } } = this.props;
    console.log(uiVar1);

    return (
      <div />
    );
  }
}

The console log look as follows:

TestUIComponent.js?34cd:98: 1
TestUIComponent.js?34cd:98: 1
TestUIComponent.js?34cd:98: 1
TestUIComponent.js?34cd:98: uiVar1() {
      return 1;
    }
TestUIComponent.js?34cd:98: uiVar1() {
      return 1;
    }

In case you can't reproduce this bug, I'm using this boilerplate: react-redux-universal-hot-example.

Can't create reselect selector using redux-ui state

I have a dumb component which shows a list of items and a text input that lets you filter the list by item name. I decorated the component with redux-ui in order to save the input value in redux-ui state and set default state and key.

Then I wanted to use a reselect selector in a container component connected to Redux store that let me pass a filtered array of item to the dumb component via props based on the input value, but I found that when mapStateToProps runs the selector for the first time redux-ui haven't already created the component key in the Store so I get undefined.

It's not clear for me from the documentarion how to accomplish such a thing or if I'm thinking it all wrong. Sorry if it's a very silly question!

Does not work with server-side rendering because of Immutable

After the state gets serialized into plain JavaScript objects on the server-side, and deserialized on the client-side, the action-reducer gets a non-default state of type Object, not Immutable Map it expects.

const defaultState = new Map({
    // ...
});

export default function reducer(state = defaultState, action) {
    // `state` is of type `Object` on state rehydration from the serialized data.

So, this line fails with an exception about missing get function:
https://github.com/tonyhb/redux-ui/blob/master/src/action-reducer.js#L96

const customReducers = state.get('__reducers');

You use Immutable objects in actions, too. This can fail if these actions get serialized and replayed later (one of the core features of Redux is replayability, mainly for testing and debugging purposes).
https://github.com/tonyhb/redux-ui/blob/master/src/action-reducer.js#L138
https://github.com/tonyhb/redux-ui/blob/master/src/action-reducer.js#L165

Having a non-serializable (non-POJO) state and actions leads to such incompatible behavior.
Please either drop Immutable entirely -- it really appears to be unnecessary -- or make the state and actions serializable by converting Immutable objects to POJO via .toJs().

Modify ui state based on non-redux-ui actions

At the moment I'm using my own UI-State reducer which, among other things, listens for the UPDATE_PATH action from redux-simple-router; I do this so I can set intitial UI state based on query strings.

Eg, if someone loads http://<myapp>/search?extra_filters=true, then I want to be able to set ui.extra_filters to true. How can I achieve this with redux-ui?

redux-form has a solution in the form of it's plugin API: http://erikras.github.io/redux-form/#/api/reducer/plugin?_k=xqjy5h

Perhaps something similar could be implemented here?

Tests

General state context

  • Single component has expected props (ui, resetUI, updateUI)
  • Single component has expected state vars from defaults
  • Child component inherits parent default vars
  • Single component updates UI state from updateUI
  • Child component updates parent context's UI state from updateUI
  • Child component adds default variables to own state and inherits parent's default state
  • Child component adds default variables to own state, updates own variables and receives correct state
  • Child component adds default variables to own state, updates parent variables and receives correct state
  • Child component adds default variables to own state, parent updates variables and parent/child receives correct state
  • Child component adds duplicate UI state variables to its own context; child state is updated separately from parent state (only child UI is affected)
  • Child component adds duplicate UI state variables to its own context; parent state is updated separately from child state (only parent UI is affected)
  • Siblings created in a loop with no key have individual UI contexts

Validation errors (above tests take care of non-errors)

  • Single @ui() component sets UI variables not defined in defaults and we throw an error
  • Child @ui() component (with no defaults) sets UI variables not defined in parent and we throw an error

Resetting state manually

  • Single component calling resetUI has its own context set to defaults
  • Child component calling resetUI has its own context set to defaults; parent remains unchanged
  • Parent component calling resetUI has its own and all child contexts set to defaults

componentWillUnmount & persisting UI

  • componentWillUnmount sets UI to undefined when unmounting if persist !== true
  • componentWillUnmount leaves UI context in place if persist === true

Key generation & shared contexts

  • Single component with key stores UI state inside specified key
  • Single component creates random key with no key specified
  • Two components sharing the same key share the same UI context (updating a variable in one ctx updates the other component's UI)

Real World Use

  • Mounting a component, unmounting, then remounting works as expected
  • Selectors from reselect connected beneath @ui() see default UI values

React 15

There is a dependency on react ^0.14.3 this causes issues when trying to use alongside react 15.

I'd suggest a move to a peerDependency and including react 15. Many other similar react ecosystem libraries seem to have gone with something like...

"peerDependencies": {
  "react": "^0.14.3 || ^15.0.1",
  "react-dom": "^0.14.3 || ^15.0.1"
}

Hopefully you are happy to make this change, this library is the last thing holding me back from a React 15 upgrade.

Cannot download v0.0.12 from npm

npm ERR! fetch failed https://registry.npmjs.org/redux-ui/-/redux-ui-0.0.12.tgz
npm WARN retry will retry, error on last attempt: Error: fetch failed with status code 404

v0.0.11 still works fine.

Uncaught TypeError: Cannot read property 'getState' of undefined

I'm very new to redux-ui but I couldn't find anything in the docs to help me out with this. I am using the react-redux-starter-kit and installed decorator support and redux-ui.

I have imported the ui reducer into the root reducer like this (rootReducer)::

import { reducer as ui } from "redux-ui";

export default combineReducers({
  counter,
  ui
});

Now in the root component I have defined the following:

import ui from "redux-ui";

@ui({
  key: "root",
  state: {
    isLoggedIn: false,
    user: null
  }
})
class Root extends React.Component { ...

Now when the app starts I get the following error:
Uncaught TypeError: Cannot read property 'getState' of undefined in ui.js:166

What could be causing this?

How to preserve ui state after remount.

Is there any options to let me preserve components' ui state? In some senerio, that component may remount to component tree.

Any thing like this ?

@ui({
  preserveOnUnmount: true,
  state: {
    foo: 'foo',
    bar: 'bar',
  }
})
class BazComponent extends React.Comopnent {}

Changing parent UI affects children

We have this basic setup:

  • Parent with UI
    • Child with UI
    • Child with UI

Each time the parent UI changes it will update the children UI as well, forcing an update. We want to keep the children pure, we do not need the parent UI settings.

I understand this can be handy in some cases, in some cases it may not be handy and will require a manual check in shouldComponentUpdate to see if the internal UI settings were updated. Is there any way to make this configurable? Just wondering what you guys think about this.

Blocks hot module reloading

Somehow, as soon as a component is connected to redux-ui it no longer displays changes in code done via hot-reloading. The same component worked just fine without ui connected to it before.

'Uncaught TypeError: state.get is not a function' after adding the reducer

I added the ui reducer as the last reducer in my combineReducers function, but I an error Uncaught TypeError: state.get is not a function which points to line 97 in action-reducer.js

Any ideas why this is not working?

My reducers/index.js:

import { combineReducers } from 'redux';
import { reducer as uiReducer } from 'redux-ui';
import session from './session';
import users from './users';

export default combineReducers({
  session,
  users,
  ui: uiReducer
});

multipe instances of the same component

i have visibilty flag on a list of items of the same component.
the only way i came up with was to merge to whole thing with the new state.
updateUI('items', { ...items, ...{ [id]: !items[id] } })
just wondering if that's the intended way.

Reset UI state of another component?

What's the best way to reset state of one component on button click in another component? Both wrapped in ui. From what i see, resetUI resets only "current" component (the one where we call it), and we can't do something like resetUI('componentKey') to reset component by key. Should i use ui reducer option for this, or there is another way?

Exception thrown after @@redux-ui/MOUNT_UI_STATE

Hi there, first I have to say big thank you for this excellent plugin.

I'm using redux-ui with my react-native application.

Mot sure maybe I'm doing something wrong, but currently I'm stuck on exception:

image

Where and how to update UI state for thunks?

Forgive me if the answer is trivial but I can't find an example in the documentation or elsewhere and I would like to give redux-ui a try and adapt my existing code to it. Where would you recommend updating the UI state for asynchronous actions wrapped around a redux-thunk such as retrieving a resource through an API?

For example I would just like to update a isLoading state specific to a component that depends on an asynchronous action (an API call, dispatching actionCreators such as IN_PROGRESS, SUCCESS which would modify the UI state). Any example or advice on how to structure and implement that with redux-ui ? Thank you.

redux-ui with redial

a relative newbie here to react , redux and redial..

If I am already using redial in a component (see below) how can I also use redux-ui (in the non decorator fashion) at the same time? I am already using provideHooks at the bottom of the file :

`import { provideHooks } from 'redial'
import React, { PropTypes } from 'react'
import { loadUnlistedVins, loadFilterData } from '../actions'
import { connect } from 'react-redux'
import UnlistedVinsFilter from '../components/UnlistedVinsFilter'

import YearFilter from '../components/YearFilter'

import { StyleSheet, css } from 'aphrodite'
import Helmet from 'react-helmet'
import { selectUnlistedVins } from '../unlistedVinsReducer'
import { getFilterData } from '../filterDataReducer'

const redial = {

/**

  • this is triggered from server/index.js
    */
    fetch: ({ dispatch, params: {filter} }) => {
    dispatch(loadFilterData())
    }
    }

const mapStateToProps = state => ({
unlistedVins: selectUnlistedVins(state),
})

const UnlistedVinsListPage = ({ unlistedVins }) => (

<YearFilter/>
<br/>
<UnlistedVinsFilter/><br/>
<table>
<thead>
<tr><th>select</th><th>ListingSubjectLine</th><th>ModelID</th><th>Year</th><th>TrimLevel</th><th>Miles</th><th>SuggestedBuyItNowPrice</th><th>VIN</th><th>ListingSite</th><th>Region</th><th>Brand</th><th>Status</th><th>Location</th><th>Date</th></tr>
</thead>
<tbody>

{
    unlistedVins.isLoading &&

    <tr><td>Loading...</td><td></td><td></td></tr>
}

 {!unlistedVins.isLoading &&  unlistedVins.unlistedVins.data &&
     unlistedVins.unlistedVins.data.map((unlistedVin, i) =>

     <tr key={unlistedVin.InventoryID}><td><input type="checkbox"/></td><td>{unlistedVin.ListingSubjectLine}</td><td>{unlistedVin.ModelID}</td><td>{unlistedVin.Year}</td><td>{unlistedVin.TrimLevel}</td><td>{unlistedVin.Miles}</td><td>{unlistedVin.SuggestedBuyItNowPrice}</td><td>{unlistedVin.VIN}</td><td>???</td><td>???</td><td>???</td><td>???</td><td>???</td><td>???</td></tr>

     )
 }
</tbody>
</table>
)

UnlistedVinsListPage.PropTypes = {
unlistedVins: PropTypes.array.isRequired

}

const styles = StyleSheet.create({
root: {
maxWidth: 500
},
title: {
fontSize: 28,
margin: '0 auto 1.5rem',
color: '#b7b7b7'
}
})

export default provideHooks(redial)(connect(mapStateToProps)(UnlistedVinsListPage))
`

Publish v0.0.12

v0.0.12 is missing from npm, which is crucial for those using Immutable js.

Single file distribution

Hi, would it be possible to provide in the package dist folder with single file for dev and minified version of this library? We are working on a project where using webpack or other similar bundler is currenly not an option, so this would help a lot.

Connect with `options` parameter

connect usually has a fourth parameter with options, one of which being withRef, which allows to access the wrapped component and thus methods on it.
I find myself in need of accessing a component's methods, but as I wrapped it with UI state, I can't figure out a way of doing so.

From my perspective, I would expect to be able to pass in another parameter to ui() with options passed on to the connect call. What do you think?

Some way to add custom Actions

Currently I'm doing the following to add custom action to my component.

let UiComponent = ui({
    key: 'procedure-groups',
    state: {
        group: null,
        editMode: [],
        lastAction: null
    }
})(ProcedureGroupComponent);
const mapStateToProps = (state) => {
    return {};
};
const mapDispatchToProps = {
    load: getProcedureGroup,
    save: saveProcedureGroup
};
export default connect(mapStateToProps, mapDispatchToProps)(UiComponent);

This feels wrong as I'm double wrapping the Component. Is there a better way to do this?

or another implementation would be...

export default ui({
    key: 'procedure-groups',
    state: {
        group: null,
        editMode: [],
        lastAction: null
    },
    mergeProps: bindActionCreators({
        load: getProcedureGroup,
        save: saveProcedureGroup
    }, store.dispatch)
})(ProcedureGroupComponent);

I think what I want is something like the following.

export default ui({
    key: 'procedure-groups',
    state: {
        group: null,
        editMode: [],
        lastAction: null
    },
    // what I really want is something that takes a function or object. If object, automatically wrap it in bindActionCreators.
    actions: (dispatch) => {
        return  bindActionCreators({
            load: getProcedureGroup,
            save: saveProcedureGroup
        }, dispatch);
    }
})(ProcedureGroupComponent);

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.