Reputation: 77
I have a problem here: I am always getting this error when I am trying to use this code in componentDidMount: Uncaught TypeError: Cannot read property 'then' of undefined
This is the code of the Component where the error occurs: components/Portfolio.jsx
import React, { Component } from 'react'
import Header from './Header'
import { connect } from 'react-redux';
import { auth } from '../actions';
import Popup from 'reactjs-popup';
import { portfolio } from '../actions'
import thunk from 'redux-thunk'
class Portfolio extends Component {
state = {
coin: undefined,
quantity: undefined,
buy_price: undefined,
coindata: undefined,
isLoaded: undefined,
}
componentDidMount(){
// this.props.fetchPortfolio();
// this.fetchCoins();
this.props.fetchPortfolio().then(() => {
this.fetchCoins();
});
}
componentDidUpdate(prevProps) {
if(this.props.auth.user !== prevProps.auth.user) {
this.fetchCoins();
}
}
submitInvestment = (e) => {
e.preventDefault();
this.props.addInvestment(this.state.coin, this.state.quantity, this.state.buy_price);
this.props.fetchPortfolio();
this.fetchCoins();
}
fetchCoins(){
let coins = this.props.portfolio.map(coin => coin.coin).join(",");
console.log(coins);
//console.log(coins)
fetch("https://min-api.cryptocompare.com/data/pricemultifull? fsyms="+coins+"&tsyms=USD")
.then(res => res.json())
.then(
(result) => {
console.log(result)
this.setState({
isLoaded: true,
coindata: result,
})
},
(error) => {
this.setState({
isLoaded: true,
error
});
}
)
}
render() {
...
}
}
}
const mapStateToProps = state => {
let errors = [];
if (state.portfolio.errors) {
errors = Object.keys(state.portfolio.errors).map(field => {
return {field, message: state.portfolio.errors[field]};
});
}
return {
user: state.auth.user,
auth: state.auth,
portfolio: state.portfolio.portfolio,
portfolioLoaded: state.portfolio.portfolioLoaded,
coin_symbol: state.coin,
errors
// errors
}
}
const mapDispatchToProps = dispatch => {
return {
addInvestment: (coin, quantity, buy_price) => {
return dispatch(portfolio.addInvestment(coin, quantity, buy_price));
},
deleteInvestment: (coin) => {
dispatch(portfolio.deleteInvestment(coin));
},
fetchPortfolio: () => {
dispatch(portfolio.fetchPortfolio());
}
}
}
export default connect(mapStateToProps, mapDispatchToProps)(Portfolio); //
This is the fetchPortfolio function in actions/portfolio.js:
export const fetchPortfolio = () => {
return (dispatch, getState) => {
let headers = {'Content-Type': 'application/json'}
let {token} = getState().auth
if (token) {
headers['Authorization'] = `Token ${token}`
}
return fetch('/api/coins/', {headers })
.then(res => {
if (res.status < 500) {
return res.json().then(data => {
return {status: res.status, data}
})
} else {
console.log('Server Error!')
throw res
}
})
.then(res => {
if (res.status === 200) {
dispatch({type: 'FETCH_PORTFOLIO', portfolio: res.data})
} else if (res.status === 401 || res.status === 403) {
dispatch({type: 'AUTHENTICATION_ERROR', data: res.data})
throw res.data
}
})
}
}
And this is the App.js code:
import React, { Component } from 'react'
import {Switch, Route, BrowserRouter, Redirect, Link} from 'react-router-dom'
import { Provider, connect } from 'react-redux'
import { createStore, applyMiddleware } from 'redux'
import thunk from 'redux-thunk'
import {auth} from './actions'
import rootReducer from './reducers'
import News from './components/News'
import NotFound from './components/NotFound'
import Login from './components/Login'
import Register from './components/Register'
import Market from './components/Market'
import Portfolio from './components/Portfolio'
let store = createStore(rootReducer, applyMiddleware(thunk))
class RootContainerComponent extends Component {
componentDidMount () {
this.props.loadUser()
}
render () {
if (this.props.auth.isLoading) {
return <p>Loading..</p>
} else {
return (
<BrowserRouter>
<Switch>
<Route exact path='/' component={News} />
<Route exact path='/login' component={Login} />
<Route exact path='/register' component={Register} />
<Route exact path='/markets' component={Market} />
<Route exact path='/portfolio' component={Portfolio} />
<Route component={NotFound} />
</Switch>
</BrowserRouter>
)
}
}
}
const mapStateToProps = state => {
return {
auth: state.auth
}
}
const mapDispatchToProps = dispatch => {
return {
loadUser: () => {
return dispatch(auth.loadUser())
}
}
}
let RootContainer = connect(mapStateToProps, mapDispatchToProps) (RootContainerComponent)
export default class App extends Component {
render () {
return (
<Provider store={store}>
<RootContainer />
</Provider>
)
}
}
I hope you can help me with the problem!
Upvotes: 0
Views: 2551
Reputation: 944
In mapDispatchToProps
your fetchPortfolio
doesn’t return a promise or anything else. You must return a promise inside it but dispatch
doesn’t return something.
You have to wait your props being updated by mapStateToProps
You have portfolioLoaded
which is mapped to your props. Just check his value in your componentWillReceiveProps
and if it’s true now you can call this.fetchCoins
Upvotes: 3