2

how to map returned Array of Objects? When i click the button to fetch the blogs, i am getting this response

image1 and image 2

Now in my app js,

import React from 'react';
import Blog from '../components/Blog';
import Form from '../components/Form';
import Root from '../components/Root';
import { Router, Route, IndexRoute, browserHistory} from 'react-router';
import axios from 'axios';
import { connect } from 'react-redux';

class App extends React.Component {

render(){

return(
	<Router history={browserHistory}>
	<Route path={'/'} component={Root}>
		<IndexRoute component={ () => (<Blog blog_posts={this.props.posts} fetchBlogs={this.props.fetchBlogs} />) } ></IndexRoute>
		<Route path={'/form'} component={Form}></Route>
	</Route>
	</Router>
);
}
}

const mapStateToProps = (state) => {
	return {
		posts: state.blogs
	};
};

const mapDispatchToProps = (dispatch) => {
return {
	fetchBlogs : () => {
	dispatch(
	{ type: "FETCHING_BLOG" },
	axios.get("https://jsonplaceholder.typicode.com/posts")
	.then( (response) => {
		dispatch({
			type: "FETCHING_SUCCESS",
			payload: response.data
		})
	} )
	.catch( (err) => {
		dispatch({
			type: "FETCHING_ERROR",
			payload: err
		})
	})
	);
	}
};
};

export default connect(mapStateToProps, mapDispatchToProps)(App);

i am passing the posts from mapStateToProps( which holds the response data) thru props into Blog Component in the IndexRoute.

in my Blog Component, iam logging the passed props (as seen in the image above) and it is passed fine. Now it is the blog_posts.. now i am mapping the blog_posts and doesnt work and returns ncaught TypeError: Cannot read property 'map' of undefined. Please explain why is it not working.. maybe blog_post should contain another array which the values shouldbe stored there??? Please kindly explain what im doing wrong

My blog component:

import React from 'react';

class Blog extends React.Component {
render(){
	console.log("Passed", this.props);
	
	let b = this.props.blog_posts.map(item => {
		console.log(item)
	});
	
	return(
	<div>
		<button onClick={() => this.props.fetchBlogs()}>Fetch Users!</button>
	</div>
	);
}
}

export default Blog;

reducer:

const initBlogState = {
	fetching: false,
	fetched: true,
	blogs: [],
	error: null
};

export default function blogReducer (state = initBlogState, action) {
	switch(action.type)
	{
		case "FETCHING_BLOG":
			state = {
				...state,
				fetching: true
			};
			break;
		case "FETCHING_SUCCESS":
			state = {
				...state,
				fetched: true,
				blogs: action.payload
			};
			break;
		case "FETCHING_ERROR":
			state = {
				...state,
				fetched: false,
				error: action.payload
			};
			break;
		default:
			break;
	}
	return state;
};

Provider:

import React from 'react';
import ReactDOM from 'react-dom';

import App from './container/App';
import { Provider } from 'react-redux';
import store from './store';

ReactDOM.render(
	<Provider store={store}>
		<App />
	</Provider>, document.getElementById('root'));

Store:

import { createStore, applyMiddleware } from 'redux';
import logger from 'redux-logger';
import blogReducer from './reducers/blogReducer';
import thunk from 'redux-thunk';

const store = createStore(
	blogReducer,
	{},
	applyMiddleware(thunk, logger())
);

export default store;

4
  • 2
    Im sorry, totally off-topic but how can you even read this with such indent style? Commented Jan 17, 2017 at 14:25
  • sorry sir will edit it Commented Jan 17, 2017 at 14:27
  • Where's your Provider ? Commented Jan 17, 2017 at 14:29
  • edited sir. thank you Commented Jan 17, 2017 at 14:33

3 Answers 3

2

Regarging the

Uncaught TypeError: Cannot read property 'map' of undefined

You can try defining default prop types for the Blog component.

Blog.defaultProps = {
    blog_posts: []
}

But this might not fix it and it might be related to the other error you are doing.

More important thing is that the map function should be used to return a transformed collection of the one on which .map is invoked. So in your case, you are not returning any object from map, you are using (I am wondering how this code did not report compilation errors because map should return a value):

let b = this.props.blog_posts.map(item => {
    console.log(item)
});

If you just want to iterate trough the collection, use .forEach insted of .map, and if your intention is to use .map to transform the collection into a new collection, then your function should return a value, not just console.log something. It should look like this:

let b = this.props.blog_posts.map(item => {
    console.log(item);
    return item; // you can transform the item here however you like
});

Although I think that there is no need to console.log anything inside a .map iteration.

Sign up to request clarification or add additional context in comments.

Comments

1

You're using axios to send an ajax request, so when you were calling map on blog_posts, the data weren't returned yet. Use redux-promise: https://github.com/acdlite/redux-promise

3 Comments

arent the data was already returned sir because it is logging in the console?
In the images, there are 2 log statements. 1 with undefined which is before the data is returned, and 1 with the correct data which is the result of running render() again after the props is changed. I suppose you got the error before rerendering
so whenever i click the button to fetch the user, it already maps (having the data undefined)?
0

Ok so Ive solved my problem. the map function is already firing(even the axios request is not done returning the data yet) when i clicked the fetch user button in my Blog component.. so i have created a function which checks the fetched state in my reducer initial state. using thus code

if (this.props.fetched === true)
    {
        console.log("passed: ", this.props);
        console.log("blogs: ", this.props.blog_post);

        let b;
        b = this.props.blog_post.blogs.map(item => {
            return console.log(item)
        });

    }

then i found out that in my initial state in my reducer, the fetched is mistakenly assigned already in true! so i changed it in false

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.