1

I am attempting to load some local json data with redux and display in react app. But i'm getting the pageId is undefined in the reducer.

Not sure what I am doing wrong here, I think it might be something wrong with how I'm passing the data but im very new to redux so i'm not sure.

Data

const page = [
   {"title":"Mollis Condimentum Sem Ridiculus"},
   {"title":"Pharetra Tellus Amet Commodo"}
]
export default page;

Action

const getPage = (pageId) => {
    const page = { pageId: pageId }
    return {
        type: 'GET_PAGE_SUCCESS',
        payload: page
    }
 }
 export default getPage

Reducer

import getPage from '../actions/actionCreators'
import pageData from './../data/pageData';


 const defaultState = pageData

 const pageReducer = (state = defaultState, action) => {
    if (action.type = 'GET_PAGE_SUCCESS') {
       state.page[action.payload.pageId].title = action.payload
     }

   return state
  }

  export default PageReducer

Component

import React, { Component, PropTypes } from 'react'
import { connect } from 'react-redux'
import getpage from '../../actions/actionCreators'

const mapStateToProps = (state, props) => {
   const page = state.page[props.pageId]
   return { page }
 }

 class Page extends Component {
    componentDidMount () {
       this.props.getpage(this.props.pageId)
  }

  render() {

       return (<div><PageContainer pageId={0} /></div>)
     }
  }

  const PageContainer = connect(mapStateToProps, { getpage })(page)

  export default Page

2 Answers 2

2

I've modified your code into a working JSFiddle for reference: https://jsfiddle.net/qodof048/11/

I tried to keep it as close to your example, but let me explain the changes I made to get it working (also note that JSFiddle does not use the ES6 import syntax).

1) Your PageContainer was not constructed correctly. The last parameter should have been a reference to the Page component (not 'page').

const PageContainer = connect(mapStateToProps, { getPageSimple, getPageAsync })(PageComponent)

2) You used PageContainer in the Page component, but PageContainer is the 'wrapper' around Page. You use PageContainer instead of Page in your render method, so it loads the data (maps state and actions).

ReactDOM.render(
    <Provider store={store}>
    <div>
      <PageContainer pageId="0" async={false} />
      <PageContainer pageId="1" async={true} />
    </div>
  </Provider>,
  document.getElementById('root')
);

3) The store was mixed up a bit. If I understood your example correctly you want to load a page into the local store from the pageData array, which simulates a server call maybe. In that case you intialState can't be pageData, but rather is an empty object. Think of it like a local database you're going to fill. The call to your action getPage then gets the page (here from your array) and dispatches it into the store, which will save it there.

const getPageSimple = (pageId) => {
  const page = pageDatabase[pageId]; // this call would be to the server

  // then you dispatch the page you got into state
  return {
    type: 'GET_PAGE_SUCCESS',
    payload: {
        id: pageId,
      page: page
    }
  }
}

4) I've added an async example to the JSFiddle to explain how you would actually fetch the page from the server (since the simple example would not be sufficient). This needs the thunk middleware for redux to work (since you need access to the dispatch method in order to async call it). The setTimeout simulates a long running call.

const getPageAsync = (pageId)=>{
    return (dispatch, getState) => {
    setTimeout(()=>{

      const page = pageDatabase[pageId]; // this call would be to the server, simulating with a setTimeout
        console.log("dispatching");
      // then you dispatch the page you got into state
      dispatch({
        type: 'GET_PAGE_SUCCESS',
        payload: {
            id: pageId,
          page: page
        }
      });
    }, 2000);
  }
}

The JSFiddle loads 2 containers, one with your simple getPage and one with the async version, which loads the title after 2 seconds.

Hope that helps you along on your react/redux journey.

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

Comments

1

Hey I see a small mistake in you component, I think. You are doing this.props.pageId, when you are setting page and not pageId on the component's props. So shouldn't it be this.props.getPage(this.props.page.pageId) instead? Could that be it?

Also a small side note, an important tip for using redux is to not mutate state. In you reducer where you are doing state.page[action.payload.pageId].title = action.payload you should probably not set state like that, but instead return a new object called newState which is identical to state, but with the title updated. It is important to treat objects as immutable in Redux. Cheers

1 Comment

Thanks, I gave your suggestion to update the component a go and still getting the same problem. Based on your other comment I suspect i have some other stuff fundamentally wrong as well. Learning is hard!

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.