Daniel Böök Daniel Böök - 2 months ago 8
React JSX Question

Initial state in React with Redux not working

Having problem with the initial state in React with Redux. It's my first application to use async calls, and it seems that there is some stuff I can't figure out.

I'm using a spreadsheet from Google as my "backend", so it will be easy for my relatives to rent out our ski lodge. It is just a spreadsheet of the weeks and if they are available or not.

By looking at the console, the data gets fetched, but something is not working.

Here is the error message:

Error message

Here is the github repo: https://github.com/Danielbook/kulan2016

And, here is the code:

index.js

import About from './components/About';
import Guest from './components/Guest';
import Booking from './containers/Booking';

import getSpreadsheetData from './actions'

const logger = createLogger();
const store = createStore(
rootReducer, compose(
applyMiddleware(thunk, promise, logger),
window.devToolsExtension ? window.devToolsExtension() : f => f)
);

const tableUrl = "https://spreadsheets.google.com/feeds/list/1QxC20NcuHzqp1Fp7Dy2gpBDbJzN4YpmjiEcr7PSpsuM/od6/public/basic?alt=json";

store.dispatch(getSpreadsheetData(tableUrl));

// Create an enhanced history that syncs navigation events with the store
// const history = syncHistoryWithStore(browserHistory, store);

ReactDOM.render(
<Provider store={store}>
<Router history={hashHistory}>
<Route path="/" component={App}>
<IndexRoute component={Home}/>
<Route path="/about" component={About}/>
<Route path="/guest" component={Guest}/>
<Route path="/booking" component={Booking}/>
</Route>
</Router>
</Provider>,
document.getElementById('app')
);


reducer-bookingdata.js

const initialState = {
spreadsheetData: [],
loading: false,
errorMsg: ''
};

export default function spreadsheet(state = initialState, action) {
switch (action.type) {
case 'SPREADSHEET_REQUEST':
return {
...state,
loading: true
};

case 'SPREADSHEET_RECEIVED':
return {
...state,
loading: false,
spreadsheetData: action.payload.data,
errorMsg: ''
};

case 'SPREADSHEET_FAIL':
return {
loading: false,
errorMsg: action.payload.error
};

default:
return state;
}
}


booking-actions.js

import fetch from 'isomorphic-fetch';

// --- Action-creators ---
function requestSpreadsheet() {
return {
type: 'SPREADSHEET_REQUEST'
}
}

function receiveSpreadsheet(data) {
return {
type: 'SPREADSHEET_RECEIVED',
payload: {
data: data
}
}
}

function receiveSpreadsheetError(error) {
return {
type: 'SPREADSHEET_FAIL',
payload: {
error: error
}
}
}

// --- API ---
function fetchTable(tableUrl) {
// Code related to API here. Should just return a promise.
return fetch(tableUrl);
}

// --- Thunks ---
export default function getSpreadsheetData(tableUrl) {
return function (dispatch, getState) {
// Tell reducers that you are about to make a request.
dispatch(requestSpreadsheet());

// Make the request, then tell reducers about
// whether it succeeded or not.
// Here, we update the app state with the results of the API call.
return fetch(tableUrl)
.then(response => response.json())
.then(data => dispatch(receiveSpreadsheet(data.feed.entry)),
error => dispatch(receiveSpreadsheetError(error)));
}
}


Booking.js

import React, {Component, PropTypes} from 'react';
import {connect} from 'react-redux';
import {Grid, Table} from 'react-bootstrap';
import TableRow from '../components/TableRow';

class Booking extends Component {
constructor(props) {
super(props);

}
render() {
return (
<Grid fluid className="pageContainer">
<h4>För att boka, skicka ett mail till oss <a href="mailto:boka@kulaniklappen.se">här!</a></h4>
<p>{this.props.errorMsg}</p>
<Table responsive>
<thead>
<tr>
<th>Ledighet</th>
<th>Vecka</th>
<th>Datum</th>
<th>Pris</th>
</tr>
</thead>
<tbody>
{this.props.spreadsheetData.map((row, i) => {
return (
<TableRow key={i} data={row} />
)
})}
</tbody>
</Table>
</Grid>
);
}
}

const mapStateToProps = (state) => {
console.log(state);
return {
spreadsheetData: state.spreadsheetData,
loading: state.loading,
errorMsg: state.errorMsg
}
};

export default connect(mapStateToProps, null)(Booking);

Answer

As i can see from error message your state structure is

{
    bookingData: {
        spreadsheetData: ...,
        loading: ...,
        errorMsg: ...
    },
    ...
}

And your mapStateToProps should be

const mapStateToProps = (state) => {
    console.log(state);
    return {
        spreadsheetData: state.bookingData.spreadsheetData,
        loading: state.bookingData.loading,
        errorMsg: state.bookingData.errorMsg
    }
};
Comments