Skip to content

Instantly share code, notes, and snippets.

@mindpivot
Created March 30, 2017 22:18
Show Gist options
  • Save mindpivot/991c03a41247e3e59bd92f03d2482bed to your computer and use it in GitHub Desktop.
Save mindpivot/991c03a41247e3e59bd92f03d2482bed to your computer and use it in GitHub Desktop.
Redux Thunk doesn't seem to be registered properly
import React from 'react';
import { render } from 'react-dom';
import App from '../shared/App';
// REDUX IMPORTS
import { Provider } from 'react-redux';
import { ConnectedRouter } from 'react-router-redux';
// build the redux store
const storeBuilder = require('../redux/store/configureStore');
const store = storeBuilder.default();
// use the same history as the redux middleware;
const history = storeBuilder.history;
render(
<Provider store={store}>
<ConnectedRouter history={history}>
<App/>
</ConnectedRouter>
</Provider>,
document.getElementById('site-wrapper')
);
import { createStore, applyMiddleware, compose } from 'redux'
import thunk from 'redux-thunk';
import { routerMiddleware } from 'react-router-redux';
import {createLogger} from 'redux-logger';
import rootReducer from '../reducers'
// history
import createHistory from 'history/createBrowserHistory';
const history = createHistory();
const middleware = [routerMiddleware(history), thunk, createLogger()];
const configureStore = preloadedState => {
const store = createStore(
rootReducer,
preloadedState,
compose(
applyMiddleware(...middleware),
window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__()
)
);
if (module.hot) {
// Enable Webpack hot module replacement for reducers
module.hot.accept('../reducers', () => {
const nextRootReducer = require('../reducers');
store.replaceReducer(nextRootReducer)
})
}
return store
};
export default configureStore;
export { history };
import fetch from 'isomorphic-fetch';
export const INVENTORY_SEARCH_LOADING = 'INVENTORY_SEARCH_INVENTORY';
export const INVENTORY_SEARCH_RESULTS = 'INVENTORY_SEARCH_RESULTS';
export const INVENTORY_SEARCH_ERROR = 'INVENTORY_SEARCH_ERROR';
export function inventorySearchLoading(isLoading) {
return {
type: INVENTORY_SEARCH_LOADING,
payload: {
isLoading
}
}
}
export function inventorySearchResults(results) {
return {
type: INVENTORY_SEARCH_RESULTS,
payload: {
isLoading: false,
results: results
}
}
}
export function inventorySearchError(error) {
return {
type: INVENTORY_SEARCH_ERROR,
payload: {
isLoading: false
},
error
}
}
export function inventorySearch(searchTerms) {
// Return a function that accepts `dispatch` so we can dispatch later.
// Thunk middleware knows how to turn thunk async actions into actions.
return (dispatch) => {
dispatch(inventorySearchLoading(true));
let apiUrl;
let merchantId = 1; // TODO: extract from user profille
if (process.env.__CLIENT__) {
apiUrl = '/api/inventory/search';
} else {
let domainUrl = process.env.INVENTORY_API_URL || 'http://my.development.url'
let pathtree = '/api/inventory/query/merchant/' + merchantId;
apiUrl = domainUrl + pathtree;
}
let options = {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
id: searchTerms.id,
merchantId,
sku: searchTerms.sku,
location: null,
zone: null,
isPickable: searchTerms.activeOnly
})
};
// add merchant ID header value to send to API from FE Server
if (!process.env.__CLIENT__) {
options.headers['MerchantId'] = merchantId;
}
return fetch(apiUrl + pathtree, options).then((response) => {
if (!response.ok) {
throw Error(response.statusText);
}
dispatch(inventorySearchLoading(false));
})
.then((response) => response.json())
.then((items) => dispatch(inventorySearchResults(items)))
.catch(() => dispatch(inventorySearchError(error)));
};
}
import { INVENTORY_SEARCH_LOADING, INVENTORY_SEARCH_RESULTS, INVENTORY_SEARCH_ERROR } from '../actions/inventoryActions';
const initialState = {
isLoading: false,
search: {
terms: {
id: '',
sku: '',
styleId: '',
name: '',
vendor: '',
location: '',
zone: '',
isPickable: true,
rows: 50
}
},
results: [],
selectedItemId: '',
selectedItem: {}
};
function inventoryReducer (state = initialState, action) {
const { type, error, payload } = action;
switch (type) {
case INVENTORY_SEARCH_LOADING:
return payload.isLoading;
case INVENTORY_SEARCH_RESULTS:
return payload.results;
case INVENTORY_SEARCH_ERROR:
return error;
default:
return state;
}
};
export default inventoryReducer;
/**
* Created by raumer on 1/24/17.
*/
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { inventorySearch } from './../../../../redux/actions/inventory'
class AdjustmentsForm extends Component {
constructor(props) {
super(props);
}
handleSubmit() {
let searchTerms = {};
// attach form elements to search terms
this.props.performSearch(searchTerms)
}
render() {
if (this.props.isLoading) {
return <p4>Loading...</p4>
}
return (
<div>
<form>
<fieldset>
<legend>search criteria</legend>
<div>
<label htmlFor="">Sku</label>
<input type="text"/>
</div>
<div>
<label htmlFor="">Style ID</label>
<input type="text"/>
</div>
<div>
<label htmlFor="">Product Name</label>
<input type="text"/>
</div>
<div>
<label htmlFor="">Vendor Brand</label>
<input type="text"/>
</div>
<div>
<label htmlFor="">active only?</label>
<input type="checkbox"/>
</div>
<div>
<label htmlFor="">Number of Rows</label>
<input type="dropdown"/>
</div>
</fieldset>
<button type="submit" onClick={this.handleSubmit()}>Search</button>
</form>
</div>
)
}
}
const mapStateToProps = (state) => {
return {
searchTerms: state.inventory.search.terms,
isLoading: state.inventory.isLoading
}
};
const mapDispatchToProps = (dispatch) => {
return {
performSearch: (searchTerms) => dispatch(inventorySearch(searchTerms))
}
};
export default connect(mapStateToProps, mapDispatchToProps)(AdjustmentsForm);
import { routerReducer } from 'react-router-redux';
import { combineReducers } from 'redux';
import authReducer from './auth';
import errorMessage from './pageErrorMessage';
import inventoryReducer from './inventoryreducer';
const rootReducer = combineReducers({
pageError: errorMessage,
auth: authReducer,
inventory: inventoryReducer,
router: routerReducer,
});
export default rootReducer;
@mindpivot
Copy link
Author

mindpivot commented Mar 30, 2017

Given this App setup, why do I get this error?

"Error: Actions must be plain objects. Use custom middleware for async actions."

at dispatch (/Users/raumer/PATH_TO_PROJECT/node_modules/redux/lib/createStore.js:166:13)
      at Object.performSearch (/Users/raumer/PATH_TO_PROJECT/app/shared/screens/inventory/adjustments/adjustmentsform.js:69:41)
      at AdjustmentsForm.handleSubmit (/Users/raumer/PATH_TO_PROJECT/app/shared/screens/inventory/adjustments/adjustmentsform.js:15:20)
      at AdjustmentsForm.render (/Users/raumer/PATH_TO_PROJECT/app/shared/screens/inventory/adjustments/adjustmentsform.js:52:57)
      at /Users/raumer/PATH_TO_PROJECT/node_modules/react-dom/lib/ReactCompositeComponent.js:796:21

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment