My reactjs setup with babeljs is show below
My action.js
export function onIncrement() {
return {
type: 'INCREMENT'
};
}
export function onDecrement() {
return {
type: 'DECREMENT'
};
}
container/App.js
import React, { Component, PropTypes } from 'react';
import { bindActionCreators } from 'redux';
import { connect } from 'react-redux';
import * as CounterActions from '../actions';
class App extends Component {
render() {
const { counter, actions } = this.props;
return (
<div>
<p>
Clicked: {counter} times
</p>
<p>
<button onClick={actions.onIncrement}>
+
</button>
</p>
<p>
<button onClick={actions.onDecrement}>
-
</button>
</p>
</div>
);
}
}
App.propTypes = {
counter: PropTypes.number.isRequired,
actions: PropTypes.object.isRequired
};
function mapStateToProps(count) {
return {
counter: count
};
}
function mapDispatchToProps(dispatch) {
return {
actions: bindActionCreators(CounterActions, dispatch)
};
}
export default connect(
mapStateToProps,
mapDispatchToProps
)(App);
containers/root.js
import React, { Component, PropTypes } from 'react';
import { Provider } from 'react-redux';
import App from './App';
export default class Root extends Component {
render() {
const { store } = this.props;
return (
<Provider store={store}>
<App />
</Provider>
);
}
}
Root.propTypes = {
store: PropTypes.object.isRequired
};
Reducer/index.js
export default function counter(count = 0, action) {
console.log(count) // this comes as object {}
console.log(action) // initially it as { type: '##INIT'}
switch (action.type) {
case 'INCREMENT':
return count + 1;
case 'DECREMENT':
return count - 1;
default:
return count;
}
}
store/configureStore.js
import { applyMiddleware, createStore } from 'redux';
import createLogger from 'redux-logger';
import thunkMiddleware from 'redux-thunk';
import rootReducer from '../reducers';
export default function configureStore(initialState = {}) {
// thunkMiddleware to handle async actions in redux
const middlewares = [thunkMiddleware];
// chrome devtool extension
let devtool;
if (NODE_ENV === 'development') {
// redux-logger to log the redux state events in window.console
const logger = createLogger({
duration: true
});
middlewares.push(logger);
// devtools - redux-chrome extension
devtool = window.devToolsExtension ? window.devToolsExtension() : undefined;
}
// store - combines reducers and enchancements to redux using middlewares
const store = createStore(
rootReducer,
initialState,
devtool,
applyMiddleware(...middlewares)
);
// hot module replacement for only for reducers
if (module.hot) {
module.hot.accept('../reducers', () => {
// default - as es6 to es5 transpile in babel make the module to export as
// module.export = somemodule.default
const nextRootReducer = require('../reducers').default;
store.replaceReducer(nextRootReducer);
});
}
return store;
}
my main.js
import 'babel-polyfill';
import React from 'react';
import { render } from 'react-dom';
import Root from './containers/Root';
import configureStore from './store/configureStore';
const initialState = window.__INITIAL_STATE__;
const store = configureStore(initialState);
render(
,
document.getElementById('root')
);
My Package.json
& i am using webpack for bundling and babel for transpiling.
When i initially run this application on i get this error below,
Further investigate this issue, i found the transpiled code as show below
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = counter;
function counter() {
var count = arguments.length <= 0 || arguments[0] === undefined ? 0 : arguments[0];
var action = arguments[1];
console.log(count, "count"); // this comes as object {}
console.log(action, "action"); // initially it as { type: '##INIT'}
switch (action.type) {
case 'INCREMENT':
return count + 1;
case 'DECREMENT':
return count - 1;
default:
return count;
}
}
My Question is:
Why my defualt parameter is injected as Object {} ?
Is this babel problem ?
Am i doing anything wrong here?
The above code only works, when i change this to below,
export default function counter(count = 0, action) {
console.log(count , "count") // this comes as object {}
console.log(action, "action") // initially it as { type: '##INIT'}
switch (action.type) {
case 'INCREMENT':
return count + 1;
case 'DECREMENT':
return count - 1;
default:
return 0;
}
}
Check your configureStore function:
export default function configureStore(initialState = {}) {
// ...
}
You setting initialState to {}, so if window.__INITIAL_STATE__ is undefined you will get {} as initial state of your reducer.
Try to change this to:
export default function configureStore(initialState = 0) {
// ...
}
There is no problems with babel output.
future:
That empty object injection is due to i am setting the initialState to = {} in configureStore.js, i changed that to undefined, it worked like a charm
import { applyMiddleware, createStore } from 'redux';
import createLogger from 'redux-logger';
import thunkMiddleware from 'redux-thunk';
import rootReducer from '../reducers';
export default function configureStore(initialState) {
// thunkMiddleware to handle async actions in redux
const middlewares = [thunkMiddleware];
// chrome devtool extension
let devtool;
if (NODE_ENV === 'development') {
// redux-logger to log the redux state events in window.console
const logger = createLogger({
duration: true
});
middlewares.push(logger);
// devtools - redux-chrome extension
devtool = window.devToolsExtension ? window.devToolsExtension() : undefined;
}
// store - combines reducers and enchancements to redux using middlewares
const store = createStore(
rootReducer,
initialState,
devtool,
applyMiddleware(...middlewares)
);
// hot module replacement for only for reducers
if (module.hot) {
module.hot.accept('../reducers', () => {
// default - as es6 to es5 transpile in babel make the module to export as
// module.export = somemodule.default
const nextRootReducer = require('../reducers').default;
store.replaceReducer(nextRootReducer);
});
}
return store;
}
For more details:
https://github.com/reactjs/redux/issues/1502#issuecomment-194151490
In your mapStateToProps function, you first need to extract count from Redux state like this :
function mapStateToProps(state) {
return {
counter: state.count
};
}
Related
I am getting error, not during compilation, but in my browser,
I have attached the files here
message.js reducer file
import store from './index';
// ACTION TYPES
const FETCH_MESSAGES = "FETCH_MESSAGES";
// ACTIONS
export const fetchMessages = ( id ) => {
console.log(store.getState());
return {
type: FETCH_MESSAGES,
payload: id
}
}
// REDUCERS
export default function reducer( state = -1, action ) {
switch(action.type) {
case FETCH_MESSAGES :
return action.payload;
default:
return state;
}
}
index.js
import { createStore, combineReducers, applyMiddleware } from 'redux';
import thunk from 'redux-thunk';
import chatReducer from './chat';
import messageReducer from './messages';
const reducer = combineReducers({
chatStore : chatReducer,
messageStore : messageReducer,
});
const store = createStore(reducer, applyMiddleware(thunk));
export default store;
Error Message
Scrrenshot of error message
I cannot set up a redux store in my application. I am not receiving any errors in the console. When I use the redux dev tools it says that there is no store detected. What am I doing wrong? Do I need to change my mapStateToProps function? It doesn't appear to be the case in the tutorials I have followed so far. My files look like the following:
index.js
import React from "react";
import ReactDOM from "react-dom";
import { createStore } from 'redux';
import {Provider} from 'react-redux';
import { reducer } from './reducer';
import App from './App';
const store = createStore(reducer)
ReactDOM.render(
<Provider store={store}>
< App / >
</Provider>,
document.getElementById("root")
);
module.hot.accept(reducer);
export default store
App.js
import React from 'react';
import { createStore } from 'redux';
import { connect, Provider } from 'react-redux';
import Map from './map/Map';
// const initialState = {
// district: ''
// };
const action = {
type: 'CHANGE_DISTRICT',
district: 'Congressional District 17'
}
// const reducer = (state = initialState, action) =>{
// switch (action.type){
// case 'CHANGE_DISTRICT':
// return {...state, district: action.district}
// default:
// return state;
// }
// return state;
// }
// const store = createStore(reducer);
class App extends React.Component {
render() {
return (
// <Provider store={store}>
<Map / >
// </Provider>
)
}
}
export default App;
reducer.js
export const initialState = {
district: ''
};
export const reducer = (state = initialState, action) =>{
switch (action.type){
case 'CHANGE_DISTRICT':
return {...state, district: action.district}
default:
return state;
}
return state;
}
Map.js
import React from 'react';
import L from 'leaflet';
import { connect } from 'react-redux';
const mapStateToProps = state => {
return {
district: state.district
};
}
class Map extends React.Component {
componentDidMount() {
// create map
this.map = L.map('map').setView([31.15, -99.90], 6);
L.tileLayer('https://{s}.tile.thunderforest.com/pioneer/{z}/{x}/{y}.png?', {
attribution: 'Pioneer Basemap by Thunderforest, a project by Gravitystorm Limited.'
}).addTo(this.map);
}
render() {
const mapStyle = {
height: '500px',
width: '100%'
}
return <div id = "map" style={mapStyle}> < /div>
}
}
export default connect(mapStateToProps)(Map);
The store should work with the changes you made but to activate the extension there is an additional step
const store = createStore(
reducer,
window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__()
);
https://github.com/zalmoxisus/redux-devtools-extension#1-with-redux
const initialState = {
district: ''
};
const reducer=(state = initialState, action)=>{
switch (action.type){
case 'CHANGE_DISTRICT':
return {...state, district: action.district}
default:
return state;
}
return state;
}
can you check this. it works now
I'm sorry if my code is extremely amateur. I just recently started working with react-redux and javascript. I feel like I am a bit spaced out when looking at tutorials when it comes to visualizing states and what the store does. So I'm trying to code something to visually see it in code. My code is similar to the default preloaded code from Visual Studio when a new project for ASP.NET Web app w/ react-redux is created. I want to just call an API using redux and pass that information to the page.
For what I've got right now, I noticed that my API is not called, as putting a red light on my actionCreator is not reached.
///////////File 1 CreaterAction and Reducer/////////////////
const requestEvents = 'REQUEST_EVENTS';
const recieveEvents = 'RECEIVE_EVENTS';
const initialState = { events: [], isLoading: false };
async function getData(url) {
const response = await fetch(url);
return response.json();
}
export const actionCreators = {
requestEvents: () => async (dispatch) => {
dispatch({ type: requestEvents});
const url = 'api\stuff';
const events = await getData(url);
dispatch({ type: recieveEvents, events });
}
};
export const reducer = (state, action) => {
state = state || initialState;
if (action.type === requestEvents) {
return {
...state,
events: action.events,
isLoading: true
};
}
return state;
};
//////////////File 2 My Actual component//////////////////
import React, { Component } from 'react';
import { bindActionCreators } from 'redux';
import { connect } from 'react-redux';
import { actionCreators } from '../store/file1';
class Events extends Component {
componenetDidMount() {
this.ensureDataFetched();
}
ensureDataFetched() {
const stuff = this.props.//!!!! Does not show .requestEvents
}
render() {
return (
<div>
<h1>Events</h1>
<p>This component demonstrates fetching data from the server and working with URL parameters.</p>
{renderData(this.props)}
</div>
);
}
}
function renderData(props) {
return (
<p>{props.events}</p>
);
}
export default connect(
state => state.events,
dispatch => bindActionCreators(actionCreators, dispatch)
)(Events);
///////////////FILE 3 Config Store//////////////////
import { applyMiddleware, combineReducers, compose, createStore } from 'redux';
import thunk from 'redux-thunk';
import { routerReducer, routerMiddleware } from 'react-router-redux';
import * as Counter from './Counter';
import * as file1 from './file1';
export default function configureStore (history, initialState) {
const reducers = {
events: file1.reducer
};
const middleware = [
thunk,
routerMiddleware(history)
];
// In development, use the browser's Redux dev tools extension if installed
const enhancers = [];
const isDevelopment = process.env.NODE_ENV === 'development';
if (isDevelopment && typeof window !== 'undefined' && window.devToolsExtension) {
enhancers.push(window.devToolsExtension());
}
const rootReducer = combineReducers({
...reducers,
routing: routerReducer
});
return createStore(
rootReducer,
initialState,
compose(applyMiddleware(...middleware), ...enhancers)
);
}
It runs just shows
Events
This component demonstrates fetching data from the server and working with URL parameters.
My guess is that it's because I haven't used/called this.props.requestEvents
I am new to React and building a Spotify App with their API. I am using Redux Promise to resolve all promises. I can see data when I console it in my reducer of the data. But when I check my console it shows mapDispatchToProps() in Connect(App) must return a plain object. Instead received [object Promise]. I am thinking is it because I'm using Redux Promise vs thunk, but shouldn't it be able to resolve them as well?
Reducer
import { NEW_RELEASES } from '../actions/types';
export default function(state = [] , action){
console.log(action)
switch(action.type){
case NEW_RELEASES:
return [ action.payload.data, ...state ];
}
return state
}
Store
import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import { createStore, applyMiddleware } from 'redux';
import App from './App';
import reducers from './reducers';
import ReduxPromise from 'redux-promise'; // Look at action creator for ReduxPromise use
const createStoreWithMiddleware = applyMiddleware(ReduxPromise)(createStore);
ReactDOM.render(
<Provider store={createStoreWithMiddleware(reducers)}>
<App />
</Provider>
, document.querySelector('#root'));
Action Creator
export const getNewReleases = () => {
console.log('ran')
let request = axios.get("https://api.spotify.com/v1/browse/new-releases?country=SE", {
headers: {
'Authorization': 'Bearer ' + accessToken
}
})
return{
type: NEW_RELEASES,
payload: request
}
App.Js
import React, { Component } from 'react';
import './App.css';
import Spotify from 'spotify-web-api-js';
import { getNewReleases } from './actions'
import { bindActionCreators } from 'redux';
import { connect } from 'react-redux';
const spotifyWebApi = new Spotify();
class App extends Component {
constructor(props) {
super(props)
const params = this.getHashParams();
this.state = {
welcome: "Welcome to SpotiDate",
accessToken: params.access_token,
loggedIn: params.access_Token ? true : false,
nowPlaying: {
name: 'Not Checked',
images: ''
}
}
if (params.access_token) {
spotifyWebApi.setAccessToken(params.access_token);
}
}
getHashParams() {
var hashParams = {};
var e, r = /([^&;=]+)=?([^&;]*)/g,
q = window.location.hash.substring(1);
while (e = r.exec(q)) {
hashParams[e[1]] = decodeURIComponent(e[2]);
}
return hashParams;
}
componentWillMount() {
spotifyWebApi.setAccessToken(this.state.accessToken)
localStorage.setItem('accessToken', this.state.accessToken);
const storedToken = localStorage.getItem('accessToken');
getNewReleases(storedToken);
}
render() {
return (
<div className="App">
<h3>{this.state.welcome}</h3>
<div>
<img src={this.state.nowPlaying.image} />
</div>
<button onClick={() => getNewReleases()}>Get New Releases</button>
<div className="new-releases">
</div>
</div>
);
}
}
const mapStateToProps = (state) => {
return{
newReleases: state.newReleases
}
}
const mapDispatchToProps = (dispatch) => {
return bindActionCreators(getNewReleases, dispatch);
}
export default connect(mapStateToProps, mapDispatchToProps)(App);
the function bindActionCreators will take 1st argument as JSON. so it should be like below.
const mapDispatchToProps = dispatch => {
return bindActionCreators(
{
getNewReleases: getNewReleases
},
dispatch
);
};
try to use Object.assign({}, state.newReleases), or you can use the spread operator like assigning the code just like return {...state,state.newReleases}
since your object is unable to be mapped to the object state
For further understanding of this, please check this link git issue - 334
Try returning you actions in mapDispatchToProps like this:
const mapDispatchToProps = (dispatch) => ({
getNewReleases: () => dispatch(getNewReleases())
})
I am trying to follow the redux tutorial on redux.js.org. I stumbled upon this " "Actions must be plain objects. Use custom middleware for async actions" error. It doesn't make sense because my actions are indeed plain objects (at least I think so), so I shouldn't be forced to use any middleware. (My attempts to use thunk also failed but this is not the concern of this question)
Here are my action creators:
export const ADD_TODO = 'ADD_TODO'
export const TOGGLE_TODO = 'TOGGLE_TODO'
export const SET_FILTER = 'SET_FILTER'
export const VisibilityFilters = {
SHOW_ALL: 'SHOW_ALL',
SHOW_COMPLETED: 'SHOW_COMPLETED',
SHOW_ACTIVE: 'SHOW_ACTIVE'
}
export function addTodo(todoText) {
return
{
type: ADD_TODO
todoText
}
}
export function toggleTodo(index) {
return
{
type: TOGGLE_TODO
index
}
}
export function setFilter(filter) {
return
{
type: SET_FILTER
filter
}
}
My reducers:
import { combineReducers } from 'redux'
import {
ADD_TODO,
TOGGLE_TODO,
SET_FILTER,
VisibilityFilters
} from '../actions'
const { SHOW_ALL } = VisibilityFilters
function todos(state = [], action) {
switch (action.type) {
case ADD_TODO:
return [
...state,
{
text: action.text,
completed: false
}
]
case TOGGLE_TODO:
return state.map((todo, index) => {
if (index === action.index) {
return Object.assign({}, todo, {
completed: !todo.completed
})
}
return todo
})
default:
return state
}
}
function visibilityFilter(state=SHOW_ALL, action) {
switch(action.type) {
case SET_FILTER:
return action.filter
default:
return state
}
}
const todoApp = combineReducers({
visibilityFilter,
todos
})
export default todoApp
...And finally the index.js (main):
import React from 'react'
import ReactDOM from 'react-dom'
import './index.css';
import App from './App';
import registerServiceWorker from './registerServiceWorker';
import { createStore } from 'redux';
import todoApp from './reducers';
import {
addTodo,
toggleTodo,
setFilter,
VisibilityFilters
} from './actions';
const store = createStore(todoApp)
// Log the initial state
console.log(store.getState())
// Every time the state changes, log it
// Note that subscribe() returns a function for unregistering the listener
const unsubscribe = store.subscribe(() =>
console.log(store.getState())
)
// Dispatch some actions
store.dispatch(addTodo('Learn about actions')) // This line causes the error.
store.dispatch(addTodo('Learn about reducers'))
store.dispatch(addTodo('Learn about store'))
store.dispatch(toggleTodo(0))
store.dispatch(toggleTodo(1))
store.dispatch(setFilter(VisibilityFilters.SHOW_COMPLETED))
// Stop listening to state updates
unsubscribe()
ReactDOM.render(<App />, document.getElementById('root'));
registerServiceWorker();
I'd appreciate if you clear the cloud for me so that I can continue my Redux journey.
You have to put the return object brakets in the same line
export function addTodo(todoText) {
return {
type: ADD_TODO
todoText
}
}