Redux : Cannot read property 'dispatch' of undefined - javascript

I'm so confused on why this is undefined. I set up store, and can even view it through Chrome's Redux Tools and it show correctly, however when I try and dispatch to the Store, I always get a Cannot read property 'dispatch' of undefined error. It's really bugging me because I have no idea what is going on. I have followed numerous tutorials letter for letter, and am still stuck with the same error message.
index.js
import React from 'react';
import ReactDOM from 'react-dom';
import { createStore } from 'redux';
import manageEmails from './reducers/manageEmails';
import App from './App';
import './index.css';
export function configureStore(){
return createStore(
manageEmails,
window.__REDUX_DEVTOOLS_EXTENSION__ &&
window.__REDUX_DEVTOOLS_EXTENSION__()
);
};
ReactDOM.render(
<App store={configureStore()} />,
document.getElementById('root')
);
manageEmails.js
export default function manageEmails(state = {
numberOfEmails: 0,
emails: [],
}, action) {
switch(action.type) {
case "ADD_USER":
return Object.assign({}, state, {
emails:state.emails.concat(action.email)
});
default:
return state;
}
}
App.js
import React, { Component } from 'react';
import './App.css';
import $ from 'jquery';
import Typed from 'typed.js';
import AboutDiv from '../src/components/AboutDiv.js'
import ContactDiv from '../src/components/ContactDiv.js'
import Navigation from '../src/components/Navigation.js'
import Background from '../src/components/Background.js'
import Overlay from '../src/components/Overlay.js'
import Emails from '../src/components/Emails.js'
import { BrowserRouter as Router, Route } from "react-router-dom"
$(document).ready(function() {
var options = {
strings: ["dj#khaled.com", "post#malone.com",
"drizzy#drake.com"],
typeSpeed: 175,
backSpeed: 20,
fadeOut: true,
loop: true,
attr: 'placeholder'
}
var typed = new Typed( (".typed"), options);
});
export class App extends Component {
render() {
return (
<Router>
<div className="App">
<Navigation />
<Background />
<Overlay />
<Emails store={this.props.store}/>
</div>
</Router>
);
}
}
export default App;
Emails.js
import React, { Component } from 'react';
export default class Emails extends Component {
constructor(props) {
super(props);
this.state = {
email: '',
};
}
handleOnSubmit(event) {
debugger
event.preventDefault();
this.props.store.dispatch({
type: "ADD_EMAIL",
email: this.state.email,
})
}
render() {
return(
<button onClick={this.handleOnSubmit.bind(this)}>
Click Me
</button>
)
}
};

Check the minimal example I created out of your code and it seems to work as intended. Code can be found at codesandbox
Also, you have a typo there. In the reducer you are checking for a different action then the one being dispatched in the Email component

Related

New Components in Application cannot connect to redux

I have created a small application and connected it to Redux. Unfortunately when creating new components and using the same exact code those new components cannot seem to connect to redux and get undefined when accessing it (using mapStateToProps).
I have tried to create new Components and connect them again to no avail. I'm kind of at loss as to why it isn't working especially since the rest of the application can connect and get the state properly
index.js:
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import { Provider } from 'react-redux'
import store from './store'
ReactDOM.render(
<Provider store={store} >
<App />
</Provider>
, document.getElementById('root'));
store.js:
const initialState = {
guessedTimezone: '',
timezone: '',
pseudo: '',
};
function rootReducer(state = initialState, action) {
console.log(action);
if (action.type === 'CHANGE_TIMEZONE') {
return Object.assign({}, state, {
timezone: action.timezone,
guessedTimezone: action.guessedTimezone
})
}
if (action.type === 'CHANGE_PSEUDO') {
return Object.assign({}, state, {
pseudo: action.pseudo,
token: action.token
})
}
return state;
}
export default rootReducer;
new Component not connecting:
import React, { Component } from 'react'
import { connect } from 'react-redux'
export class TestPseudo extends Component {
render() {
console.log(this.props.pseudo);
return (
<div>
{this.props.pseudo}
</div>
)
}
}
const mapStateToProps = state => {
return {
pseudo: state.pseudo
}
}
export default connect(mapStateToProps)(TestPseudo)
Here for example this.props.pseudo returns undefined when, if the connection happens, it should return the value if i understand it correctly and yet it shows undefined
EDIT:
App.js as per requested :
import React, { Component } from 'react'
import { connect } from 'react-redux'
import Homepage from './Components/Homepage';
import moment from 'moment';
import moment_timezone from 'moment-timezone';
import HeaderApp from './Components/HeaderApp';
import { TestPseudo } from './Components/TestPseudo';
export class App extends Component {
async componentDidMount() {
let tz = moment.tz.guess(true);
let date = moment(new Date()).local();
let timezone = date['_i'].toString().split('(')[1].split(')')[0];
this.props.dispatch({
type: 'CHANGE_TIMEZONE',
guessedTimezone: tz,
timezone: timezone
})
console.log(`Guessed timezone: ${tz} (${timezone})`);
}
_showHomepage() {
if (this.props.showHomepage && this.props.loaded) {
return (
<div style={styles.mainWindow}>
{/*<Homepage click={this._handleClick} />*/}
<TestPseudo />
</div>
)
}
}
_showHeader() {
return (
<div>
<HeaderApp />
</div>
)
}
render() {
return (
<div>
{this._showHeader()}
{this._showHomepage()}
</div>
)
}
}
const styles = {
mainWindow: {
height: '100vh',
width: '100vw'
}
}
const mapStateToProps = state => {
return {
guessedTimezone: state.guessedTimezone,
timezone: state.timezone,
};
};
export default connect(mapStateToProps)(App);
I call that new Component instead of my old Component. The homepage can connect but not the new one so i think it's not a problem of emplacement
I think its here
import { TestPseudo } from './Components/TestPseudo';
You are importing the non-connected component. Try this
import TestPseudo from './Components/TestPseudo';
For your understanding, exporting as default can be imported like so;
export default Component
import WhateverName from ....
Named export like const or in your case class;
export class Component
import { Component } from ...
So use brackets when Named, and skip brackets when default.

State not updating in React/Rudux Application

So, I have searched high and low for a solution to this problem and haven't found an answer. Any closely related questions end up solving the problem by fixing state mutation issues which I am pert near positive I don't have. Also, I have done similar things a few times before that have worked just fine, and referring back to the code for those projects shown no significant differences with what I'm doing here.
I have a small React app that will get bigger over time so I'm using Redux for state management. Currently I have a main App component that will eventually be the parent for my routing, but for now I just have a single component inside of it that will be a Login page. The current thing I am trying to accomplish is simply to change the value of showCreateAccountFlyout from false to true when I click ButtonPseudoAnchor in the Login page.
App.js
import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
// import { BrowserRouter as Router, Route, Switch } from 'react-router-dom';
/* ---- Routes ----- */
import Login from './scenes/Login';
/* ----- Redux Store ----- */
import store from './redux/configureStore';
/* ----- Styles ----- */
import reset from './globalStyles/reset.scss';
export default class App extends React.Component<void> {
render() {
return (
<Provider store={store}>
<Login />
</Provider>
)
}
}
Login.js
import React from 'react';
import { Link } from 'react-router-dom';
import ButtonBasic from '../components/buttons/ButtonBasic';
import ButtonRow from '../components/buttons/ButtonRow';
import ButtonPseudoAnchor from '../components/buttons/ButtonPseudoAnchor';
import FlyoutFullScreen from '../components/containers/FlyoutFullScreen';
import FormElementBasic from '../components/formElements/FormElementBasic';
import PageBasic from '../components/containers/PageBasic';
import { connect } from 'react-redux';
import { toggleCreateAccountFlyout } from '../redux/actions/loginActions';
/* ----- Styles ----- */
import loginStyles from './loginStyles.scss';
class Login extends React.Component {
constructor() {
super();
this.onClickHandler = this.onClickHandler.bind(this);
}
onClickHandler() {
this.props.toggleCreateAccountFlyoutHandler(!this.props.showCreateAccountFlyout);
}
render() {
return (
<PageBasic contextualModifier="loginPage">
<div className={loginStyles.loginContainer}>
<div className={loginStyles.baphometLogo}>baphomet</div>
<FormElementBasic
type="text"
placeholderText="Username or Email"
/>
<FormElementBasic
type="password"
placeholderText="Password"
/>
<ButtonRow rowAlignment="center">
<ButtonBasic
buttonText="Enter"
buttonType="primary"
/>
</ButtonRow>
<ButtonPseudoAnchor onClickFunc={this.onClickHandler}>Create Account</ButtonPseudoAnchor>
</div>
<FlyoutFullScreen showFlyout={this.props.showCreateAccountFlyout} />
</PageBasic>
);
}
}
const mapStateToProps = state => {
return {
showCreateAccountFlyout: state.loginReducer.showCreateAccountFlyout
}
};
const mapDispatchToProps = dispatch => {
return {
toggleCreateAccountFlyoutHandler: showCreateAccountFlyout =>
dispatch(toggleCreateAccountFlyout(showCreateAccountFlyout))
}
}
export default connect(mapStateToProps, mapDispatchToProps)(Login);
loginActions.js
export const TOGGLE_CREATE_ACCOUNT_FLYOUT = 'TOGGLE_CREATE_ACCOUNT_FLYOUT';
export function toggleCreateAccountFlyout(showCreateAccountFlyout) {
return {
type: TOGGLE_CREATE_ACCOUNT_FLYOUT,
payload: showCreateAccountFlyout
}
}
loginReducer.js
import { TOGGLE_CREATE_ACCOUNT_FLYOUT } from '../actions/loginActions';
export default function loginReducer(state = {
showCreateAccountFlyout: false
}, action) {
switch(action.type) {
case TOGGLE_CREATE_ACCOUNT_FLYOUT:
return { ...state, showCreateAccountFlyout: action.payload };
default:
return state;
}
}
reducers/index.js
import { combineReducers } from 'redux';
import loginReducer from './loginReducer';
const rootReducer = combineReducers({
loginReducer
});
export default rootReducer;
configureStore.js
import { applyMiddleware, createStore } from 'redux';
import thunk from 'redux-thunk';
import rootReducer from './reducers';
const middleware: Function = applyMiddleware(thunk);
export default createStore(rootReducer, middleware);
As I step through everything, the new showCreateAccountFlyout value is being passed along, it just appears to never get passed back to the Login component from the reducer. Maybe there is something super simple I'm missing? I dunno.

How to access redux variables and functions from deep components

I'm a bit confused about redux implementation.
Let's say my app has this component structure:
-App
--ProfilationStep
---ProfilationStep1
----React-Select (http://jedwatson.github.io/react-select/)
I need to use redux because the app is going to grow bigger and deeper, so I started by setting up Actions, Reducers and Action types for the React-Select component. I also set the mapStateToProps in the App.js file.
Now I need to know how to pass/access the data stored in redux to other components (React-Select for example) and how to edit it with the actions I declared.
This is my index.js file
import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import { createStore } from 'redux';
import ProfilationSelectReducer from './components/reducers/profilationSelect';
import './index.css';
import App from './App';
import registerServiceWorker from './registerServiceWorker';
const store = createStore(
ProfilationSelectReducer
);
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>, document.getElementById('root'));
registerServiceWorker();
This is my App.js
import React, { Component } from 'react';
import PropTypes from 'prop-types'
import { bindActionCreators} from 'redux'
import Profilation from './components/Profilation'
import ProfilationStep from './components/Profilation/ProfilationStep'
import { connect } from 'react-redux';
import * as SelectActionCreators from './components/actions/profilationSelect'
import 'react-select/dist/react-select.css';
class App extends Component {
static propTypes = {
steps: PropTypes.array.isRequired
};
render() {
console.log(this.props)
const { dispatch, steps } = this.props;
const changeValue= bindActionCreators(SelectActionCreators.changeValue, dispatch);
const stepComponents = this.props.steps.map((step, index) => (
<ProfilationStep
key={index}
index={index}
step={step}
/>
));
return (
<div className="repower-app">
{ stepComponents }
</div>
);
}
}
const mapStateToProps = state => ({
steps:state.steps
});
export default connect(mapStateToProps)(App);
This is my ProfilationStep.js file
import React, { Component } from 'react';
import PropTypes from 'prop-types'
import ProfilationStep1 from './ProfilationStep1'
import ProfilationStep2 from './ProfilationStep2'
import ProfilationStep3 from './ProfilationStep3'
import ProfilationStep4 from './ProfilationStep4'
import ProfilationStep5 from './ProfilationStep5'
const ProfilationStep = props =>
<div className='ProfilationStep'>
{props.index===0 &&
<ProfilationStep1
step={props.step}
/>
}
{props.stepIndex===2 &&
<ProfilationStep2
handleSelect={props.handleSelect}
handleInput={props.handleInput}
expend={props.expend}
period={props.period}
light={props.light}
gas={props.gas}
/>
}
{props.stepIndex===3 &&
<ProfilationStep3
handleSelect={props.handleSelect}
environment={props.environment}
/>
}
{props.stepIndex===4 &&
<ProfilationStep4
flexibility={props.flexibility}
handleSelect={props.handleSelect}
/>
}
{props.stepIndex===5 &&
<ProfilationStep5
customize={props.customize}
handleSelect={props.handleSelect}
/>
}
</div>
export default ProfilationStep
This is my ProfilationStep1.js file
import React, { Component } from 'react';
import Select from 'react-select';
import PropTypes from 'prop-types'
var jobOptions = [
{ value: 'edilizia', label: 'Edilizia' },
{ value: 'editoria', label: 'Editoria' },
{ value: 'educazione', label: 'Educazione' }
];
const ProfilationStep1 = props =>
<div className='ProfilationStep'>
La mia attività si occupa di <Select
name="job"
value={props.step.job}
onChange={e => props.changeValue(e.target.value)}
options={jobOptions}
/>
</div>
ProfilationStep1.propTypes = {
//isComplete: PropTypes.bool.isRequired,
//isActive: PropTypes.bool.isRequired
job: PropTypes.string.isRequired,
service: PropTypes.string.isRequired,
handleSelect: PropTypes.func.isRequired
}
export default ProfilationStep1
This is my reducer
import * as ProfilationSelectActionTypes from '../actiontypes/profilationSelect';
const initialState = {
steps: [{
job: "",
service: ""
}],
}
export default function ProfilationSelectReducer (state=initialState, action){
switch(action.type){
case ProfilationSelectActionTypes.CHANGE_VALUE:
return {
...state,
steps:[{
job: action.value
}]
};
default:
return state;
}
}
This is my actiontypes file
export const CHANGE_VALUE ='profilationSelect/CHANGE_VALUE';
and, finally, this is my actions file
import * as ProfilationSelectActionTypes from '../actiontypes/profilationSelect';
export const changeValue = value =>{
return{
type: ProfilationSelectActionTypes.CHANGE_VALUE,
value
}
}
Thank you for any help
You are definitely on the right way.
The solution is simple: You bind your state to the react props. With the props, you can do whatever you like (e.g. pass them to react-select). If you want to modify it, you have to map "mapDispatchToProps", where you map functions, which execute your actions to the props. This works the same as "mapStateTopProps":
End of App.js (import your actions file on top, named "profilationSelectActions" here):
const mapStateToProps = state => ({
steps:state.steps
});
const mapDispatchToProps = dispatch => ({
updateJobValue: (value) => dispatch(profilationSelectActions.changeValue(value))
}
// Also add here mapDispatchToProps
export default connect(mapStateToProps, mapDispatchToProps)(App);
Now the function "updateJobValue" is available in the props of your app.js. You can now easily pass it down to your components and to the onChange event of react-select:
In your ProfilationStep1.js change this line:
onChange={e => props.changeValue(e.target.value)}
To this (after you passed the function updateJobValue down)
onChange{e => props.updateJobType(e.target.value)}
After that, updateJobType should go all the way up to App.js and then dispatch the action. After that, the application will re-render with the new steps.

Redux data is giving me undefined when calling on a component rendering

I am utilizing thunk with react and redux. My action creator executes an API call and returns data in a property "data" and my reducer returns that object. I have this returned object mapped to props in my component. Its an array of 16 items (each item is an image url). when I console.log(this) I can click through and see the data, but if I go further like console.log(this.props.showGallery.imageLinks) it shows undefined.
Another situation is that when I render { this.props.showGallery.imageLinks } I can clearly see all the text of the items in the array on my web page but when I use .map on it, the console says cannot read property "map" of undefined and the web page is just empty. Am I doing this wrong? How can I make this data like normally?
Am I understanding redux concepts wrongly?
actions.js
export const SHOW_GALLERY = 'SHOW_GALLERY';
import axios from 'axios';
// FETCH THE IMAGES
export const actionGallery = () => {
return ( dispatch ) => {
axios.get('../images')
.then(res => {
if (res.status === 200) {
return dispatch({ type: SHOW_GALLERY, data: [...res.data] });
}
})
.catch(err => console.error(err));
}
}
reducer
images.js
import { HEAD_SELECTED, SHOW_GALLERY } from '../actions/actions';
import { actionSelectHeadImg } from '../actions/actions';
import { actionGallery } from '../actions/actions';
// Show the image links from an array
export function showGallery(state={}, action) {
switch(action.type) {
case SHOW_GALLERY:
return Object.assign({}, state, { imageLinks: new Array(action.data) })
default:
return state;
}
}
combined Reducers for above:
import React from 'react';
import { combineReducers } from 'redux';
import { showGallery, headSelected } from './images';
// Combine all your reducers to this
const allReducers = combineReducers({
showGallery,
headSelected
});
export default allReducers;
component / container
Gallery.js
import React from 'react';
import ReactDOM from 'react-dom';
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import { actionGallery } from '../actions/actions';
import cheerio from 'cheerio';
class Gallery extends React.Component {
constructor(props) {
super(props);
this.state = {
data: []
}
this.props.actionGallery();
}
render() {
return (
<div>
<h1>This is the Gallery.</h1>
<br />
<div className="container">
<div className="row">
<div className="col-md-8">
<h2>H2 h2 h2 2h2 </h2>
{ this.props.showGallery.imageLinks.forEach((i, index) => {
<p>i</p>
}) }
</div>
</div>
</div>
</div>
);
}
}
function mapStateToProps(state) {
return {
showGallery: state.showGallery,
headSelected: state.headSelected,
newState: state
}
}
function mapDispatchToProps(dispatch) {
return bindActionCreators({
actionGallery,
actionSelectHeadImg
}, dispatch)
}
export default connect(mapStateToProps, mapDispatchToProps)(Gallery);
A regular component that just holds the other container/components
import React from 'react';
import ReactDOM from 'react-dom';
import Gallery from './containers/Gallery';
import HeadingImg from './containers/HeadingImg';
class App extends React.Component {
render() {
//console.log(this.props.actionGallery())
return (
<div>
<center>
<h3>SELECTED IMAGE:</h3>
<br />
<HeadingImg />
<hr />
<Gallery />
</center>
</div>
);
}
}
export default App;
TOP LEVEL COMPONENT (MAIN COMPONENT)
import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import { createStore, applyMiddleware } from 'redux';
import App from '../Components/Earth/app';
import allReducers from '../Components/Earth/reducers';
import thunk from 'redux-thunk';
const store = createStore(allReducers, applyMiddleware(thunk));
ReactDOM.render(
<Provider store={store}>
<App store={store}/>
</Provider>
, document.getElementById("root"));
I'm assuming when you create your store, you only have the one reducer. If that is the case then your assumption about 'state.showGallery' existing doesn't. Instead imageLinks will be in state without the 'showGallery'.
If my assumption is correct, then you should change your mapStateToProps to have showGallery as:
showGallery: { imageLinks: state.imageLinks },

Problems to dispatch action in React/Redux

I´m pretty new to React and Redux and have some issue during my first steps with it. I tried to follow the examples in the Redux Doc´s, but it´s hard for me to understand everything, because every example is jumping between ES5 - 6 or even 7 syntax.
However, When I try to dispatch an action I got the following error
Uncaught TypeError: (0 , _index2.default) is not a function
Error Message
I know that SO Community doesn´t prefer so much code within one Question, but I don´t know where the problem is coming from. Sorry for that!
These is my Code:
Index.js
import 'babel-polyfill'
import React from 'react'
import { render } from 'react-dom'
import { Provider } from 'react-redux'
import App from './containers/App'
import configureStore from './store/configureStore'
const store = configureStore()
render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById('root')
)
My Store
import { createStore, applyMiddleware } from 'redux'
import thunkMiddleware from 'redux-thunk'
import createLogger from 'redux-logger'
import index from '../reducers'
export default function configureStore(preloadedState) {
const store = createStore(
index,
preloadedState,
applyMiddleware(thunkMiddleware, createLogger())
)
if (module.hot) {
// Enable Webpack hot module replacement for reducers
module.hot.accept('../reducers', () => {
const nextRootReducer = require('../reducers').default
store.replaceReducer(nextRootReducer)
})
}
return store
}
My Container Component
import React, { Component, PropTypes } from 'react'
import AddTodo from '../components/AddTodo'
import { connect } from 'react-redux'
import addItem from '../actions/index'
class App extends Component {
constructor(props) {
super(props)
this.handleClick = this.handleClick.bind(this)
}
handleClick(e){
console.log("click")
console.log(e);
const {dispatch} = this.props
dispatch(addItem(e));
}
render() {
return (
<div>
< h1 > Hallo </h1>
<AddTodo handleAddItem={this.handleClick}/>
</div>
)
}
}
App.propTypes = {
dispatch: PropTypes.func.isRequired
}
function mapStateToProps(state){
return {
AddTodo
}
}
export default connect (mapStateToProps)(App)
My Child Component:
import React, { Component, PropTypes } from 'react'
import addItem from '../actions/index'
export default class AddTodo extends Component {
constructor(props) {
super(props)
this.handleClick = this.handleClick.bind(this)
this.state = {newItem: ''}
}
onChange(e){
console.log("change")
console.log(e.target.value);
this.setState({newItem: e.target.value})
}
handleClick(e){
this.props.handleAddItem(this.state.newItem)
// const {dispatch} = this.props
// console.log("clickc")
// console.log(this.state.newItem);
// dispatch(addItem(this.state.newItem))
}
render() {
return (
<div>
<h3>Add Item </h3>
<input
type="text"
value={this.state.newItem}
onChange={this.onChange.bind(this)}
/>
<button onClick={this.handleClick}>Hallo</button>
</div>
)
}
}
The Reducer
export default (state = [], action) => {
switch (action.type){
case 'ADD_ITEM':
return action.item
}
}
And Finally the action
export function addItem(item){
console.log("addTOdo")
return {
type: 'ADD_ITEM',
item
}
}
I hope someone can help me here, sitting since several hours and don´t understand what is happening.
You are not exporting action creator as default. You need either
export default function addItem(item){
console.log("addTOdo")
return {
type: 'ADD_ITEM',
item
}
}
or
import {addItem} from '../actions/index'

Categories

Resources