Giter Club home page Giter Club logo

redux-async-connect's Introduction

ReduxAsyncConnect for React Router

npm version

How do you usually request data and store it to redux state? You create actions that do async jobs to load data, create reducer to save this data to redux state, then connect data to your component or container.

Usually it's very similar routine tasks.

Also, usually we want data to be preloaded. Especially if you're building universal app, or you just want pages to be solid, don't jump when data was loaded.

This package consist of 2 parts: one part allows you to delay containers rendering until some async actions are happening. Another stores your data to redux state and connect your loaded data to your container.

Installation & Usage

Using npm:

$ npm install redux-async-connect
import { Router, browserHistory } from 'react-router';
import { ReduxAsyncConnect, asyncConnect, reducer as reduxAsyncConnect } from 'redux-async-connect'
import React from 'react'
import { render } from 'react-dom'
import { createStore, combineReducers } from 'redux';

// 1. Connect your data, similar to react-redux @connect
@asyncConnect({
  lunch: (params, helpers) => Promise.resolve({id: 1, name: 'Borsch'})
})
class App extends React.Component {
  render() {
    // 2. access data as props
    const lunch = this.props.lunch
    return (
      <div>{lunch.name}</div>
    )
  }
}

// 3. Connect redux async reducer
const store = createStore(combineReducers({reduxAsyncConnect}), window.__data);

// 4. Render `Router` with ReduxAsyncConnect middleware
render((
  <Provider store={store} key="provider">
    <Router render={(props) => <ReduxAsyncConnect {...props}/>} history={browserHistory}>
      <Route path="/" component={App}/>
    </Router>
  </Provider>
), el)

Server

import { renderToString } from 'react-dom/server'
import { match, RoutingContext } from 'react-router'
import { ReduxAsyncConnect, loadOnServer, reducer as reduxAsyncConnect } from 'redux-async-connect'
import createHistory from 'history/lib/createMemoryHistory';
import {Provider} from 'react-redux';
import { createStore, combineReducers } from 'redux';

app.get('*', (req, res) => {
  const history = createHistory();
  const store = createStore(combineReducers({reduxAsyncConnect}));

  match({ routes, location: req.url }, (err, redirect, renderProps) => {

    // 1. load data
    loadOnServer(renderProps, store).then(() => {

      // 2. use `ReduxAsyncConnect` instead of `RoutingContext` and pass it `renderProps`
      const appHTML = renderToString(
        <Provider store={store} key="provider">
          <ReduxAsyncConnect {...renderProps} />
        </Provider>
      )

      // 3. render the Redux initial data into the server markup
      const html = createPage(appHTML, store)
      res.send(html)
    })
  })
})

function createPage(html, store) {
  return `
    <!doctype html>
    <html>
      <body>
        <div id="app">${html}</div>

        <!-- its a Redux initial data -->
        <script dangerouslySetInnerHTML={{__html: `window.__data=${serialize(store.getState())};`}} charSet="UTF-8"/>
      </body>
    </html>
  `
}

Comparing with other libraries

There are some solutions of problem described above:

  • AsyncProps It solves the same problem, but it doesn't work with redux state. Also it's significantly more complex inside, because it contains lots of logic to connect data to props. It uses callbacks against promises...
  • react-fetcher It's very simple library too. But it provides you only interface for decorating your components and methods to fetch data for them. It doesn't integrated with React Router or Redux. So, you need to write you custom logic to delay routing transition for example.
  • react-resolver Works similar, but isn't integrated with redux.

Redux Async Connect uses awesome Redux to keep all fetched data in state. This integration gives you agility:

  • you can react on fetching actions like data loading or load success in your own reducers
  • you can create own middleware to handle Redux Async Connect actions
  • you can connect to loaded data anywhere else, just using simple redux @connect
  • finally, you can debug and see your data using Redux Dev Tools

Also it's integrated with React Router to prevent routing transition until data is loaded.

Contributors

Collaboration

You're welcome to PR, and we appreciate any questions or issues, please open an issue!

redux-async-connect's People

Contributors

andrewmclagan avatar arkist avatar horizonxp avatar jorrit avatar toxahak 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  avatar

redux-async-connect's Issues

Update the readme and API ?

It seems the example in readme.md is not working in v1.0.0-rc2, it's very confusing and I don't know how to use this in the right way. ๐Ÿ˜ข

Uncaught TypeError: asyncItems.map is not a function

function wrapWithDispatch(asyncItems) {  
  return asyncItems.map(function (item) {
  ...

It seems it should be an array? But in the example:

@asyncConnect({
  lunch: (params, helpers) => Promise.resolve({id: 1, name: 'Borsch'})
})

I don't know how to do next...

How to get the router query props

Hi ! I'm trying to use redux async connect to pre-fetch data for a component server side.
I need not only the route params (provide by the "params" parameter of reduxAsyncConnect), but also the router query (containing a "page" parameter that i need to fetch the correct data). Any idea about how i could do that ? I tried to use redux-simple-router but in the fetch data, the correct location doesn't seem to be populated in the store.

this.props.lunch example is populated async object

In the example decorator
@asyncConnect({ lunch: (params, helpers) => Promise.resolve({id: 1, name: 'Borsch'}) })
the decorated component has this.props.lunch available with a value of {id: 1, name: 'Borsch'}
such that you can do this.props.lunch.name.

However, for me this.props.lunch has a value of { loading: false, loaded: true, data: { id: 1, name: 'Borsch' } } such that to access the name I need to do this.props.lunch.data.name

I feel like there is a missing then() from the example? Any tips to debug?

postinstall step not babel 6 friendly

If redux-async-connect is included in a project that uses Babel 6, and they don't specify a .babelrc in their project that doesn't use stage-0 preset, they'll get the following postinstall error:

> [email protected] build /Users/d4/code/universal-redux-starter/node_modules/redux-async-connect
> babel ./modules --stage 0 --loose all -d lib --ignore '__tests__'

SyntaxError: modules/ReduxAsyncConnect.js: Unexpected token (51:19)
  49 |
  50 | class ReduxAsyncConnect extends React.Component {
> 51 |   static propTypes = {
     |                    ^
  52 |     components: array.isRequired,
  53 |     params: object.isRequired,
  54 |     location: object.isRequired,

I suggest either updating to use babel-cli at ~6.4 or use a prepublish step rather than a postinstall.

Unable to run npm shrinkwrap with redux-async-connect

โšก npm shrinkwrap
npm ERR! Darwin 14.5.0
npm ERR! argv "/Users/csekharveera/.nvm/versions/node/v4.2.5/bin/node" "/Users/csekharveera/.nvm/versions/node/v4.2.5/bin/npm" "shrinkwrap"
npm ERR! node v4.2.5
npm ERR! npm v2.14.12

npm ERR! Problems were encountered
npm ERR! Please correct and try again.
npm ERR! extraneous: [email protected] /Users/csekharveera/Sites/app-f-vertical/node_modules/redux-async-connect/node_modules/history
npm ERR!
npm ERR! If you need help, you may report this error at:
npm ERR! https://github.com/npm/npm/issues

npm ERR! Please include the following file with any support request:
npm ERR! /Users/csekharveera/Sites/app-f-vertical/npm-debug.log

npm-debug.log

0 info it worked if it ends with ok
1 verbose cli [ '/Users/csekharveera/.nvm/versions/node/v4.2.5/bin/node',
1 verbose cli '/Users/csekharveera/.nvm/versions/node/v4.2.5/bin/npm',
1 verbose cli 'shrinkwrap' ]
2 info using [email protected]
3 info using [email protected]
4 verbose stack Error: Problems were encountered
4 verbose stack Please correct and try again.
4 verbose stack extraneous: [email protected] /Users/csekharveera/Sites/app-f-vertical/node_modules/redux-async-connect/node_modules/history
4 verbose stack at shrinkwrap_ (/Users/csekharveera/.nvm/versions/node/v4.2.5/lib/node_modules/npm/lib/shrinkwrap.js:37:15)
4 verbose stack at /Users/csekharveera/.nvm/versions/node/v4.2.5/lib/node_modules/npm/lib/shrinkwrap.js:31:5
4 verbose stack at /Users/csekharveera/.nvm/versions/node/v4.2.5/lib/node_modules/npm/lib/ls.js:47:30
4 verbose stack at /Users/csekharveera/.nvm/versions/node/v4.2.5/lib/node_modules/npm/node_modules/read-installed/read-installed.js:142:5
4 verbose stack at /Users/csekharveera/.nvm/versions/node/v4.2.5/lib/node_modules/npm/node_modules/read-installed/read-installed.js:263:14
4 verbose stack at cb (/Users/csekharveera/.nvm/versions/node/v4.2.5/lib/node_modules/npm/node_modules/slide/lib/async-map.js:47:24)
4 verbose stack at /Users/csekharveera/.nvm/versions/node/v4.2.5/lib/node_modules/npm/node_modules/read-installed/read-installed.js:263:14
4 verbose stack at cb (/Users/csekharveera/.nvm/versions/node/v4.2.5/lib/node_modules/npm/node_modules/slide/lib/async-map.js:47:24)
4 verbose stack at /Users/csekharveera/.nvm/versions/node/v4.2.5/lib/node_modules/npm/node_modules/read-installed/read-installed.js:263:14
4 verbose stack at cb (/Users/csekharveera/.nvm/versions/node/v4.2.5/lib/node_modules/npm/node_modules/slide/lib/async-map.js:47:24)
5 verbose cwd /Users/csekharveera/Sites/app-f-vertical
6 error Darwin 14.5.0
7 error argv "/Users/csekharveera/.nvm/versions/node/v4.2.5/bin/node" "/Users/csekharveera/.nvm/versions/node/v4.2.5/bin/npm" "shrinkwrap"
8 error node v4.2.5
9 error npm v2.14.12
10 error Problems were encountered
10 error Please correct and try again.
10 error extraneous: [email protected] /Users/csekharveera/Sites/app-f-vertical/node_modules/redux-async-connect/node_modules/history
11 error If you need help, you may report this error at:
11 error https://github.com/npm/npm/issues
12 verbose exit [ 1, true ]

How to invoke on client side?

Is there a simple way I am overlooking to invoke a client side reload of data gathered by asyncConnect decorator?

Server-side React render was discarded

Followed the setup and changed my existing code, got this error in console:
Server-side React render was discarded. Make sure that your initial render does not contain any client-side code.

It seems dest.firstChild.attributes['data-react-checksum'] is undefined, and I guess somewhere there is a mismatch between server / client rendering.

(I'm also using webpack isomorphic tools, i.e., )

Great work btw, this is definitely the cleanest approach to async loading!

Error handling in loadOnServer

Hi,
I was looking at the code for loadOnServer and was thinking that the error handling should come after '.then'. My code had a reference error and it took me a while to figure out why loadOnServer wasn't resolving. Any reason behind why it's before?

export function loadOnServer({ components, params }, store, helpers) {
  return Promise.all(asyncConnectPromises(filterAndFlattenComponents(components), params, store, helpers))
    .catch(error => console.error('reduxAsyncConnect server promise error: ' + error)).then(() => {
      store.dispatch(endGlobalLoad());
    });
}

load data again on client side

I use ReduxAsyncConnect with react-intl

const component = (
  <Router render={(props) => <ReduxAsyncConnect {...props} helpers={{client}} filter={item => !item.deferred} />} history={browserHistory}>
    {getRoutes(store)}
  </Router>
);

ReactDOM.render(<Provider key="provider" store={store}>
  <IntlProvider locale={locale} messages={localeMessages}>
    {component}
  </IntlProvider>
</Provider>, dest);

But code in asyncConnect run again on the client side:

@asyncConnect([{
  promise: ({store: {dispatch, getState}}) => {
    const promises = [];
    // something here ...

    return Promise.all(promises);
  }
}])

Getting error: `TypeError: asyncItems.reduce is not a function` with v1.0.0-rc2

When upgrading to v1.0, I am seeing:

[1] TypeError: asyncItems.reduce is not a function
[1]     at /Users/austinmao/Sites/aditive-frontend/node_modules/redux-async-connect/lib/ReduxAsyncConnect.js:117:35
[1]     at Array.map (native)
[1]     at loadAsyncConnect (/Users/austinmao/Sites/aditive-frontend/node_modules/redux-async-connect/lib/ReduxAsyncConnect.js:114:68)
[1]     at Object.loadOnServer (/Users/austinmao/Sites/aditive-frontend/node_modules/redux-async-connect/lib/ReduxAsyncConnect.js:142:10)
[1]     at /Users/austinmao/Sites/aditive-frontend/src/server.js:107:7
[1]     at /Users/austinmao/Sites/aditive-frontend/node_modules/react-router/lib/match.js:65:5
[1]     at /Users/austinmao/Sites/aditive-frontend/node_modules/react-router/lib/createTransitionManager.js:110:13
[1]     at done (/Users/austinmao/Sites/aditive-frontend/node_modules/react-router/lib/AsyncUtils.js:81:19)
[1]     at /Users/austinmao/Sites/aditive-frontend/node_modules/react-router/lib/AsyncUtils.js:87:7
[1]     at getComponentsForRoute (/Users/austinmao/Sites/aditive-frontend/node_modules/react-router/lib/getComponents.js:9:5)

My code looks like this: https://gist.github.com/austinmao/2b6835414ba740911a5f

Since API docs have not been updated, I cannot tell what has changed to troubleshoot this.

Cannot use `connect` and `asyncConnect` on the same component

I'm reviewing the simple-router branch on RRUHE: erikras/react-redux-universal-hot-example@4567347

Implementing it in my own project, everything works great! I like how I can define the static method reduxAsyncConnect and dispatch from there.

I was exploring using the decorator, but using that would prevent me from connecting to the rest of redux state.

Reading the code, is store available within

We could resolve this a few ways. One way would be to change the API of @asyncConnect to accept params that pass through to @connect. Example:

@asyncConnect(asyncMapStateToProps, [...normal connect params])

Example with real reducers

Hey,

I've just seen this pr erikras/react-redux-universal-hot-example#833 which looks exactly like what I need to do in my own app as well (redux-router -> redux-simple-router + changing from middleware to load props to something like redux-async-connect).

The example in the README is for a very basic promise without dispatch so here are my thoughts:

  • what is helper? looking at the PR above i see that i can put basically anything in it
  • in the AppComponent, the second param is store and not helpers and it uses a static method that fetches data without putting it back into a field like the decorator in the example which redux will do for you in mapStateToProps anyway, which is a nicer API imo

reduxAsyncProps being called after initial dispatch on client

Hi,

I am using redux-async-connect with universal-redux. I am using it like so:

static reduxAsyncConnect(params, store, helpers) {
    const {dispatch} = store;

    return dispatch(getData('Product', params.productId))
        .then(({name, upc, price, topology}) =>
            dispatch(initialize(form, {name, upc, price, topology}, fields)));
}

However when I dispatch my first action after being rendered on the client, it calls reduxAsyncConnect. Is this by design? How can I stop the function from being called on an initial dispatch of an action?

How do you get access to params and store in v1.0 decorator?

Prior to v1.0 that was released today, you could do:

static reduxAsyncConnect(params, store) { ... }

https://github.com/erikras/react-redux-universal-hot-example/blob/master/src/containers/Widgets/Widgets.js shows that you can do:

@asyncConnect([{
  deferred: true,
  promise: ({store: {dispatch, getState}}) => {
    if (!isLoaded(getState())) {
      return dispatch(loadWidgets());
    }
  }
}])

I am trying to convert code I had before to v1.0 where I am using params and store. Would you add this to your docs?

Option to not store result?

Would it make sense to provide an option that would allow the result of the promise to not be stored by key? For example, I'm just interested in being able to fire off a bunch of promises... their results will be handled by the reducers, so I don't need a duplicate copy of the data stored under reduxAsyncConnect.

Thank you!

Incorrectly maps state to props

Cool library! I'm trying to integrate in my project, I've followed readme and added:
@asyncConnect({ lunch: (params, store, helpers) => Promise.resolve({id: 1, name: 'Borsch'}) })
decorator, but in my components when I sue lunch it it doesn't return {id: 1, name: 'Bosh'} but object that has loading,loaded properties and data property that contains actual data. Is that how it's supposed to work, but perhaps not documented?

Server-side rendering problem

Hi, I'm having trouble rendering on the server. My app worked when I was using React-Router, but when trying to use this library my app no longer renders. The redux store is still serialized to the browser correctly, and the data looks as expected. However, no HTML is rendered.

I have debugged my code, and have found that on the server, everytime the ReduxAsyncConnect.render() method is called, propsToShow is always null:

render() {
    const {propsToShow} = this.state;
    return propsToShow && this.props.render(propsToShow);
  }

Here is my component:

class Homepage extends React.Component {

    static contextTypes = {
        store: React.PropTypes.object.isRequired
    };

    static reduxAsyncConnect(params, store) {
        const {dispatch, getState} = store;
        const promises = [];
        return Promise.all(promises);
    }

    render() {
        return (
            <div>
                <h2>Homepage</h2>
            </div>
        );
    }

}

export default Homepage;

No errors occur on the server. I know this isn't a lot to go on, but any assistance would be appreciated. I'm running out of ideas...

Thanks, Adam.

redux-thunk support?

Right now my async actions use redux-thunk, so they return functions that return promises... is there anyway to handle this in redux-async-connect?

Right now I have to do something like:

@asyncConnect({
lunch: (params, { store: {dispatch, getState}}) => dispatch(getLunch)(dispatch, getState)
})

Thanks!

Possible to run reduxAsyncConnect in order?

Thanks for this project.

In my project I always load user's data on all pages - so in the very root component () there is a reduxAsyncConnect method which does that.
Then in all children component they also fetch data they need - but assume user's data is loaded.

However this project seems to flatten all reduxAsyncConnect and run them simultaneously.

Would it be better if it keeps the depending tree based on component tree?

missing properties on the first render

It seems that it take some small amout of time for props to propagate. I think they should be available from the beginning. Compare this two blocks of code. Search for //change in second example.

@asyncConnect({
  users: (props, helpers) => helpers.client.getUsers()
})
export default class Users extends Component {
  static propTypes = {
    users: PropTypes.object,
  }
  render() {
    const {users} = this.props;
    return
        <div>
        {users && users.loaded
            <div>...</div>
        }
        </div>;
  }
}

a little bit nicer way

@asyncConnect({
  users: (props, helpers) => helpers.client.getUsers()
})
export default class Users extends Component {
  static propTypes = {
    users: PropTypes.object.isRequired, //change 1
  }
  render() {
    const {users} = this.props;
    return
        <div>
        {users.loaded //change 2
            <div>...</div>
        }
        </div>;
  }
}

Decorator example incorrect

Following the example in the README doesn't yield correct props:

@asyncConnect({
  lunch: (params, helpers) => Promise.resolve({ id: 1, name: 'Borsch' })
})

screenshot

The asyncConnect reducer has a nested key, data. So the example needs to be modified to this.props.data.name. Should reduxAsyncConnect reducer be modified to account for this nested key?

confuse about arguments of loadOnServer

redux-async-connect is awesome! But the docs is not very completed. There is nowhere to find docs about api loadOnServerwhich I get trouble with. After debugging, I found the problem is the arguments of loadOnServer. I follow the example:

loadOnServer(renderProps, store).then(() => {

      // 2. use `ReduxAsyncConnect` instead of `RoutingContext` and pass it `renderProps`
      const appHTML = renderToString(
        <Provider store={store} key="provider">
          <ReduxAsyncConnect {...renderProps} />
        </Provider>
      )

      // 3. render the Redux initial data into the server markup
      const html = createPage(appHTML, store)
      res.send(html)
    })

and I found in source code loadOnServer only has one argument(the npm version):

function loadOnServer(args) {
  var result = loadAsyncConnect(args);
  if (result.async) {
    result.promise.then(function () {
      args.store.dispatch((0, _asyncConnect.endGlobalLoad)());
    });
  }
  return result.promise;
}

while in github, it's right with es2015:

export function loadOnServer({ components, params }, store, helpers) {
  return Promise.all(asyncConnectPromises(filterAndFlattenComponents(components), params, store, helpers))
    .catch(error => console.error('reduxAsyncConnect server promise error: ' + error)).then(() => {
      store.dispatch(endGlobalLoad());
    });
}

So which is right? Now I temporarily fix it like this, which also react-redux-universal-hot-example]'s version:

loadOnServer({...renderProps, store}).then(() => {
    const component = (
        <Provider store={store} key='provider'>
            <div>
                <ReduxAsyncConnect {...renderProps} />
            </div>
        </Provider>
    );

    const template = ReactDOM.renderToString(<Html component={component} store={store}/>);

    res.send('<!doctype html>\n' + template);
});

Cannot read property 'loaded' of undefined

After adding this to UR (bdefore/universal-redux#52), upon loading the page without any asyncConnect, I get the error: Uncaught TypeError: Cannot read property 'loaded' of undefined. The error isn't source mapped to anything and there's no reference to loaded anywhere in the universal-redux-starter that I'm using to verify things are working correctly.

Integrating with Immutable.js

Hi,

Thanks for this library. I just wonder if this library can be integrated with Immutable.js. The problem is the current integration of isLoaded function depended on this.context.store.getState().reduxAsyncConnect.loaded;. If we can have a selector function, this would be nice

Router route change to asyncConnect()'d component loses helper?

When I load page A and navigate to page B by clicking a react-router , I get an error about my asyncConnect helper being undefined, specifically TypeError: Cannot read property 'get' of undefined using a modified version of the api helper (https://github.com/erikras/react-redux-universal-hot-example/blob/master/src/helpers/ApiClient.js).

In the code below, I confirmed that on initial page load in the browser, asyncHelpers is an object in the form of {client: ... }

      <Provider store={store} key="provider">
          <Router render={(props) =>
            <ReduxAsyncConnect {...props} helpers={ asyncHelpers } />
        } history={history} routes={routes} />
      </Provider>

Here is one of the async methods. On initial page load, client is as expected. After routing (including back button), client is undefined.

export function getArticles() {
  return {
      types: [ ARTICLE_REQUEST, ARTICLE_SUCCESS, ARTICLE_FAILURE ],
      promise: (client) => {
          console.log(client); // logs correctly on initial load, but is undefined after routing
          return client.get('/api/articles')
      }
  }

Anything obvious come to mind?

Redirect if promise fails

Hi,
I'm wondering what the best way is to redirect to a different component if a static reduxAsyncConnect method on a component falls. For example, if I'm trying to render a user-specific component and the user provides the wrong info, how do I redirect them back to the homepage when we are already committed to rendering the user page?

How to dispatch action client side only?

My use case: I need some actions to dispatch only on the client side. This includes on first page load. Right now I have something like:

@asyncConnect([{
    promise: ({ store: { dispatch, getState } }) => {
        if( !__SERVER__ ) {
            return dispatch( clientOnly() );
        }
    }
}]);

However this doesn't execute on the client side on first page load. It only executes if I navigate to the page at a later time.

See also erikras/react-redux-universal-hot-example#971

Way to trigger load manually

What about scenario with the refresh button on the page that enables user to grab fresh data without clicking around navigation.

I have small idea how this can be achived. You can add reload function on the same level we have loading and loaded properties. That function should just be the proxy to call again the promise funcion provided in @asyncConnect.

load data deferred

Hi, I'm trying to figure out how to fetch 2 things: 1 always on server and client, and the second one only on server. I'm trying to follow this code: erikras/react-redux-universal-hot-example#928

But if I do in that way, with filter only on client I always fetch both things. Because it's not filtered on server code in any way.

I've tryed to add filter on loadOnserver function in this way:

      loadOnServer(
        {
          ...renderProps,
          store,
          helpers: {client},
          filter: (item) => !item.deferred,
        }
      ).then(() => {

and deferred thing looks like this:

@asyncConnect([{
  deferred: true,
  promise: (options) => {
    return options.store.dispatch(loadDeferredThing(options.params.id));
  },
}])

And it works! It do not make this request (loadDeferredThing) on server.

The problem is not doing on client neither :/

Only when I go to other place in the app and back both request are done

loadState overwritten for each request

If i use reduxAsyncConnect in multiple components that are being rendered, loadState is overwritten in some situations (race condition). Rather than replace loadState as is being done now:

case LOAD:
      return {
        ...state,
        loadState: {
          [action.key]: {
            loading: true,
            loaded: false
          }
        }
      };

i suggest merging loadStates and only replacing the keys that match.

IE10 - Unable to get property 'store' of undefined or null reference

Hi,

I have some problems with IE10.
return this.context.store... gets Unable to get property 'store' of undefined or null reference.

_createClass(ReduxAsyncConnect, [{
        key: 'isLoaded',
        value: function isLoaded() {
          return this.context.store.getState().reduxAsyncConnect.loaded;
        }
}]);

I'm using babel 6 with the config below aswell as babel-polyfill for promises.

{
    'presets': [
        'react',
        'es2015'
    ],
    'plugins': [
        'transform-object-rest-spread',
        'transform-decorators-legacy'
    ]
}

Any idea of what might be wrong?

Question: Is data retrieved on every route change?

I have a structure as follows:

App.js:


@asyncConnect([{
    key: 'config',
    promise: ({helpers}) => helpers.client.get('config')
}])
@connect(
    state => ({
        config: state.reduxAsyncConnect.config,
        configLoad: state.reduxAsyncConnect.loadState.config
    })
)
export default class App extends Component {
...
}
@asyncConnect([{
    key: 'media',
    promise: ({helpers, params}) => helpers.client.get(`media/${params.uuid}`)
}])
@connect(
    state => ({
        media: state.reduxAsyncConnect.media,
        mediaLoad: state.reduxAsyncConnect.loadState.media
    }),
    {pushState: push}
)
export default class Container extends Component {
...
render() {
<div> ...
{this.props.children}
</div>
}
}

It seems that when i navigate throughout my app, changing routes, when the children of Container are changed/altered, it is triggering a load of the asyncConnect decorator for both App and Container every time. Is there a way to say, "hey, this data is loaded already, we dont need to look for it again"? Something like a shouldComponentUpdate but for asyncConnect to prevent it from dispatching an unnecessary call?

Thanks

Initial rendering works fine on the server, but returns `<noscript>` in browser.

I'm building a universal React app with Redux and ReactRouter.

I needed to load some data asynchronously from the server and was advised to use your library. It mostly works fine, but for some reason the initial browser rendering returns the empty noscript tag, so I'm seeing the following in the browser:

Instead, figure out why the markup being generated is different on the client or server:
(client) <noscript data-reacti
(server) <div class="admin-hom

Interestingly, after that the page loads, props are initialized and everything works as expected including replacing views without reloading the page etc. I was wondering what could be the cause of this. I'm using the same logic for loading data in browser as I do on the server and my browser-side routing part is essentially this:

window.onload = function() {
    const store = createStore(combineReducers({reduxAsyncConnect}));
    ReactDOM.render(
        <Provider store={store} >
            <Router history={browserHistory} 
                render={(props) => <ReduxAsyncConnect {...props} />} >
                <Route path='/' component={ViewComposite} />
                <Route path='/profile/:urlCode' component={ProfileComposite} />
                <Route path='/admin' component={AdminComposite}  />
            </Router>
        </Provider>,
        document.getElementById('viewMount')
    );
}

In the component file, I'm loading data using Axios:

const mapStateToProps = {
    data: (params, helpers) => {
        const url = 'http://localhost:9000/api/data/view';
        const request = axios.get(url);
        return request.then(function (response) {
            return response.data;
        })
    }
};

class ViewComposite extends React.Component {
 //...
}

export default asyncConnect(mapStateToProps)(ViewComposite);

If I understand correctly, the fact that we're returning a promise should have postponed the rendering in the browser until data is here. Is it possible to get more insight into what's going on behind the scenes and why it behaves differently?

Edited - Removed irrelevant details.

asyncItems.map is not a function

I'm running into an issue with the asyncConnect decorator on the 1.0.0-rc2 version. The exact same decorator was working without issue on 0.13. If I'm reading this commit correctly, we have to pass an array instead of an object now?

The error:

/Users/bartolkaruza/Development/Projects/dmm/dmm-web/node_modules/redux-async-connect/lib/asyncConnect.js:116
[1]   return asyncItems.map(function (item) {
[1]                     ^
[1] 
[1] TypeError: asyncItems.map is not a function
[1]     at wrapWithDispatch (/Users/bartolkaruza/Development/Projects/dmm/dmm-web/node_modules/redux-async-connect/lib/asyncConnect.js:116:21)

The decorator that causes the error;

@asyncConnect({
  segments: (params, helpers) => {
    return Promise.resolve();
  }
})
class Segments extends Component {

  render() {
    console.log(this.props.segments);
    return (
        <div>
          <h1>
            Segments
          </h1>
        </div>
    )
  }
}

Object.entries is not a function

After using components instead of component property for my routes I got this exception in browser (Chrome). Server-side-rendering is OK.

This happens in both 0.1.13 and 1.0.0-rc2.

Loading data gets frozen.

Hei, thanks for great project but i have a issue and im not sure if this is bug or problem with my setup,

i have reducer like this https://gist.github.com/tonis2/e39a16d198b689d80a8c

now on client i have

import React from 'react';
import { connect } from 'react-redux'
import { asyncConnect } from 'redux-async-connect';
import { getData } from '../../reducers/getData'
@asyncConnect([{
  promise: ({store: {dispatch, getState}}) => {
      return dispatch(getData());
  }
 }])
@connect(state => ({teasers: state.Data}))
export default class dashboard extends React.Component {

componentDidMount() {
  console.log(this.props.teasers)
}
  render() {
    return (
      <section id="dashboard">
      </section>
    );
  }
}

Seems okay ? but it will never start the reducer action, and the data will be empty.
Only after i press commit on redux-devtools it will load the data :/
Reducers action seems to get stuck

Support for nested components?

Hey,

I have two depth nested components, each has its own @asyncConnect,

I'd like in the @asyncConnect's outer component to refer data dispatched in the inner component but I don't see the dispatched data when invoking getState() in the reducers.

I didn't dig into the code flow of this component, but, should it be supported? (the methods are called in the right order),

Thanks.

@asyncConnect breaks getChildContext?

Hi,

So, I have some routes and one surrounding them.

<Route component={ApplicationContext}>
<Route path="start" component={StartHandler} />
...
</Route>

ApplicationContext sets upp some context for the rest of the app like this:

export default
class ApplicationContext extends React.Component {
    getChildContext() {
        var state = this.context.store.getState();

        var getEnv = function(name) {
            return state.env[name];
        };

        var getAsset = function(assetUrl) {
            return state.assets[assetUrl] || assetUrl;
        };

        return {
            location: this.props.location,
            getEnv: getEnv,
            getAsset: getAsset
        };
    }

    render() {
        return (
            <ApplicationComponent children={this.props.children} />
        );
    }
}

ApplicationContext.displayName = 'ApplicationContext';

ApplicationContext.propTypes = {
    location: React.PropTypes.object.isRequired
};

ApplicationContext.contextTypes = {
    store: React.PropTypes.object.isRequired
};

ApplicationContext.childContextTypes = {
    location: React.PropTypes.object,
    getEnv: React.PropTypes.func,
    getAsset: React.PropTypes.func
};

So far so good. Now I have some general data that I want to load regardless of what route you access. I thought the ApplicationContext could handle this so I added the following:

import {asyncConnect} from 'redux-async-connect';
import {isLoaded, load} from '/reducers/mydata';

@asyncConnect([{
    promise: ({store}) => {
        if (!isLoaded(store.getState().mydata)) {
            return store.dispatch(load());
        }
    }
}])
export default
class ApplicationContext extends React.Component {
...

Now I get
"TypeError: Cannot read property 'getState' of undefined"
For this line:
var state = this.context.store.getState();

Is this a bug or am I doing this wrong?

Thanks!

Uncaught TypeError: mapStateToProps[key] is not a function

Not sure where I am going wrong but I am trying to use this purely client side (not a universal app) and fetch data from an external api before the component/s load but I keep getting this error

Uncaught TypeError: mapStateToProps[key] is not a function

Here is my reducer index

import { combineReducers } from 'redux';
import { reducer as formReducer } from 'redux-form';
import { reducer as reduxAsyncConnect } from 'redux-async-connect'
import { items } from './items';
import { flows } from './flows';

const rootReducer = combineReducers({
  reduxAsyncConnect,
  form: formReducer,
  items,
  flows
});

export default rootReducer;

Here is where I configure the store

export default function configureStore(initialState) {
  const logger = createLogger({
    collapsed: true,
    predicate: () =>
    process.env.NODE_ENV === `development`, 
  });

  const enhancer = compose(
      applyMiddleware(
          thunkMiddleware,
          logger
      )
  )

  const store = createStore(
       rootReducer,
       initialState,
       enhancer);

  if (module.hot) {
    // Enable Webpack hot module replacement for reducers
    module.hot.accept('../reducers', () => {
      const nextRootReducer = require('../reducers').default;
      store.replaceReducer(nextRootReducer);
    });
  }

  return store;
}

here is my main file

import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import { Router, hashHistory } from 'react-router';
import { ReduxAsyncConnect } from 'redux-async-connect'
import configureStore from './store/configureStore';
import routes from './routes';

const store = configureStore();

ReactDOM.render(
  <Provider store={store} key="provider">
    <Router render={(props) => <ReduxAsyncConnect {...props} filter={item => !item.deferred} history={hashHistory}  />} >
        {routes}
    </Router>
  </Provider>,
  document.getElementById('root')
);

Here is the component I am trying to load

import React, { Component, PropTypes } from 'react';
import { asyncConnect } from 'redux-async-connect';

@asyncConnect([{
   key: 'flows',
    promise: ({ store: { dispatch, getState } }) => {
        return dispatch(fetchCollections());
    }
}])
export class Flows extends Component {

    static propTypes = {
        flows: PropTypes.object,
    };

   .... left out rest

For the asyncConnect part I am very confused as to what exactly to include here to make sure the data is fetched. I want to check the state for my "flows" part of the global state, see if it is present and if not fetch it from the external api. Also, I am unclear when and if I need to use the @connect decorator. Anyways, any help is appreciated.

Prepublish not ran ?

Just downloaded the latest version and the lib directory doesn't exist (ie babel compilation didn't happen)

Tried to run manually it doesn't succeed for as i'm using babel 5 and doesn't know about presets

rc3 -> rc4 breaks server side rendering

I am using the erikras/react-redux-universal-hot-example boilerplate, which depends on this library.

When upgrading from rc3 to rc4, server side rendering breaks completely. Here is the implementation of redux-async-connect on the server:

loadOnServer({...renderProps, store, helpers: {client}}).then(() => {
  const component = (
    <Provider store={store} key="provider">
      <ReduxAsyncConnect {...renderProps} />
    </Provider>
  );

  res.status(200);

  global.navigator = {userAgent: req.headers['user-agent']};

  res.send('<!doctype html>\n' +
    ReactDOM.renderToString(<Html assets={webpackIsomorphicTools.assets()} component={component} store={store}/>));
});

I don't get any errors, but none of the components are output in the renderToString.

Did something change about the loadOnServer API that needs to be adjusted in the code above?

modifying state

Hi,
I have scenario where I need to load some data from the server before rendering the view and that is well covered by that lib, but what about scenario that modifies such data (for example editing or load more that loads and add more items to the list), in such cases would you still recommend this lib?

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.