reactjs - Redux Observable, React, componentDidMount fetch from API cannot get properties from objects -
import { fetchposts } '../actions'; import react, {component} 'react'; import {bindactioncreators, dispatch} 'redux'; import {connect} 'react-redux'; import proptypes 'prop-types'; import map 'lodash/fp/map'; import flatten 'lodash/fp/flatten'; import sortby 'lodash/fp/sortby'; import compose 'lodash/fp/compose'; import take 'lodash/fp/take'; import _ 'lodash'; class postsindex extends component { state = { posts: [] }; componentdidmount() { this.props.fetchposts(); } displayposts () { //console.log(post) works, console.log(post.title) returns undefined. return _.map(this.props.posts, (post)=>{debugger;console.log(post.title);}); } render() { if(this.props.posts.length === 0) { return (<div>loading...</div>); } return (<ul>{this.displayposts()}</ul>); } } function mapstatetoprops(state) { return { posts: (state.posts) ? state.posts : [] }; } function mapdispatchtoprops (dispatch) { return bindactioncreators({fetchposts: fetchposts}, dispatch); } export default connect(mapstatetoprops, mapdispatchtoprops)(postsindex);
i can console.log(post) in
displayposts () { //console.log(post) works, console.log(post.title) returns undefined. return _.map(this.props.posts, (post)=>{debugger;console.log(post.title);}); }
but if try console.log(post.title) undefined.
likewise if try like:
displayposts () { //console.log(post) works, console.log(post.title) returns undefined. return _.map(this.props.posts, (post)=>{return <div>post.title</div>;}); }
i nothing back.
down here can see result of console.log(). former comes epic latter 1 component.
here there's link repo did open: https://github.com/deviad/redux-router-playground
the problem in reducer (found linked repo):
export default function postsreducer(state=[], action) { switch (action.type) { case actiontypes.fetch_posts_fullfilled: // problem: return [ ...state, action.payload ]; default: return state; } };
action.payload
array, place inside array, array of arrays. when map on this.props.posts
1 result, actual array of posts. when logging, didn't notice.
// problem: return [ ...state, action.payload ];
instead, could return array as-is:
return action.payload;
while above solution imo acceptable (and let's honest, shipping code #1 priority), still not idiomatic way use redux. instead, think of redux database. how store (aka normalize) these in database? if answered "indexed id" you're right!
so redux state might this:
{ posts: { '123': { id: '123', title: 'first title' }, '456': { id: '456', title: 'second title' } } }
here's 1 way might that:
export default function postsreducer(state = {}, action) { switch (action.type) { case actiontypes.fetch_posts_fullfilled: return action.payload.reduce((acc, post) => { acc[post.id] = post; return acc; }, { ...state }); // use object.assign if object-spread // syntax isn't supported default: return state; } };
because variations of common, many times nested, choose use normalizr library instead:
import { normalize, schema } 'normalizr'; const postschema = new schema.entity('posts'); export default function postsreducer(state = {}, action) { switch (action.type) { case actiontypes.fetch_posts_fullfilled: // use object.assign if object-spread // syntax isn't supported return { ...state, ...normalize(action.payload, [postschema]).entities.posts }; // etc
since in case need them array of posts in ui container, has utilities denormalizing well, or can object.values
if supported:
function mapstatetoprops(state) { return { posts: object.values(state.posts) }; }
the normalize()
call returns array of ids might find useful store in redux somewhere, or use object.keys(state.posts)
on-demand when need it--this because prevents synchronization issues, it's not practical perf reasons if number of items massive. that's issue worry when happens.
you may wondering why on earth go trouble if we're going denormalize again; full answer long winded, short gist consistency, ease of future state updates, , quick "post id" lookup later views. major part of makes redux great, otherwise becomes time-travelling glorified getter/setter, not worth boilerplate.
this discussed in normalizing state shape section of redux docs.
Comments
Post a Comment