【发布时间】:2020-10-25 09:48:28
【问题描述】:
我是使用 Node.js 的 React/redux 新手。我正在开发一个全栈应用程序,该应用程序在服务器端使用 Node.js,在客户端使用 React/Redux。该应用程序的功能之一是为当地提供当前和八天的天气预报。 Weather 路由是从客户端的菜单选择中选择的,该菜单选择对应于执行 axios.get 的服务器端路由,该路由伸出并使用天气 api(在本例中为 Darksky)并传回 JSON 的那部分与当前天气状况和八天天气预报有关的 api 对象。 API JSON 对象还有更多内容,但应用会消耗整个 JSON 对象的“当前”和“每日”部分。
我已经编写了服务器端 axios “get” 的独立版本,它成功地访问了 Darksky API 并返回了我正在寻找的数据。因此,我有理由相信我的代码将正确地带回我需要的数据。我的问题在于:当我尝试在我的 React 组件中渲染数据时,预测对象是未定义的。当然,这意味着没有要渲染的内容。
我已经查看了我的代码,阅读了大量文档,甚至浏览了可以帮助我找到问题的教程,但我仍然无法解决问题。所以,我被困住了,非常感谢一些帮助。调试过程完成后,您仍然在下面代码中的大部分注释将被删除。
我正在包含与问题相关的代码块:
我的反应组件
// client/src/components/pages/functional/Weather.js
import React, { useEffect } from 'react';
import { connect } from 'react-redux';
import PropTypes from 'prop-types';
import Moment from 'react-moment';
import Spinner from '../../helpers/Spinner'
import { getWeather } from '../../../redux/actions/weather'
const Weather = ({ getWeather, weather: { forecast, loading } }) => {
// upon load - execute useEffect() only once -- loads forecast into state
useEffect(() => { getWeather(); }, [getWeather])
return (
<div id='page-container'>
<div id='content-wrap' className='Weather'>
{ loading ?
<Spinner /> :
<>
<div className='WeatherHead box mt-3'>
<h4 className='report-head'>Weather Report</h4>
</div>
{/* Current Weather Conditions */}
<h6 className='current-head'>Current Conditions</h6>
<section className='CurrentlyGrid box mt-3'>
/* additional rendering code removed for brevity */
<span><Moment parse='HH:mm'>`${forecast.currently.time}`</Moment></span>
/* additional rendering code removed for brevity */
</section>
</>
}
</div>
</div>
);
};
Weather.propTypes = {
getWeather: PropTypes.func.isRequired,
weather: PropTypes.object.isRequired
};
const mapStateToProps = state => ({ forecast: state.forecast });
export default connect( mapStateToProps, { getWeather } )(Weather);
我的 React Action Creator
// client/src/redux/actions/weather.js
import axios from 'axios';
import chalk from 'chalk';
// local modules
import {
GET_FORECAST,
FORECAST_ERROR
} from './types';
// Action Creator
export const getWeather = () => async dispatch => {
try {
// get weather forecast
const res = await axios.get(`/api/weather`);
console.log(chalk.yellow('ACTION CREATOR getWeather ', res));
// SUCCESS - set the action -- type = GET_WEATHER & payload = res.data (the forecast)
dispatch({
type: GET_FORECAST,
payload: res.data
});
} catch (err) {
// FAIL - set the action FORECAST_ERROR, no payload to pass
console.log('FORECAST_ERROR ',err)
dispatch({
type: FORECAST_ERROR
});
};
};
我的 React 减速器
// client/src/redux/reducers/weather.js
import {
GET_FORECAST,
FORECAST_ERROR,
} from '../actions/types'
const initialState = {
forecast: null,
loading: true
}
export default (state = initialState, action) => {
const { type, payload } = action
switch (type) {
case GET_FORECAST:
return {
...state,
forecast: payload,
loading: false
}
case FORECAST_ERROR:
return {
...state,
forecast: null,
loading: false
}
default:
return state
}
}
我的节点路线
// server/routes/api/weather.js
const express = require('express');
const axios = require('axios');
const chalk = require('chalk');
const router = express.Router();
// ***** route: GET to /api/weather
router.get('/weather', async (req, res) => {
try {
// build url to weather api
const keys = require('../../../client/src/config/keys');
const baseUrl = keys.darkskyBaseUrl;
const apiKey = keys.darkskyApiKey;
const lat = keys.locationLat;
const lng = keys.locationLng;
const url = `${baseUrl}${apiKey}/${lat},${lng}`;
console.log(chalk.blue('SERVER SIDE ROUTE FORECAST URL ', url));
const res = await axios.get(url);
// forecast -- strip down res, only using currently{} & daily{}
const weather = {
currently: res.data.currently,
daily: res.data.daily.data
};
console.log(chalk.yellow('SERVER SIDE ROUTE FORECAST DATA ', weather));
// return weather
res.json({ weather });
} catch (error) {
console.error(chalk.red('ERR ',error.message));
res.status(500).send('Server Error');
}
});
module.exports = router;
与路由有关的我的 Express 服务器中间件(只是为了彻底)
// server/index.js
/* code deleted for brevity */
// define routes
app.use('/api/users', require('./routes/api/users'));
app.use('/api/auth', require('./routes/api/auth'));
app.use('/api/weather', require('./routes/api/weather'));
app.use('/api/favorites', require('./routes/api/favorites'));
/* code deleted for brevity */
如果包含的代码 sn-ps 不够用,repo 位于此处:https://github.com/dhawkinson/TH12-BnBConcierge
在此先感谢您的帮助。
***** 更新 *****
-
我注意到我在客户端的 actions/weather.js 和 reducers/weather.js 以及服务器端的 routes/api/weather.js 中的控制台日志都没有触发。这告诉我这些模块一定不能执行。这可以解释为什么我在 client/src/components/pages/functional/Weather.js 中收到错误“无法读取未定义的属性‘当前’”。显然,我在这个链条中缺少一个环节。我只是看不到它是什么。
-
我尝试了一个小的重构,基于下面的输入。我试图查看是否存在某种命名冲突。这就是我在我的 React 功能组件中所做的:
// client/src/components/pages/functional/Weather.js
...
const mapStateToProps = state => ({weather: { forecast: state.forecast, loading: state.loading }});
...
没用。
【问题讨论】:
标签: node.js reactjs redux react-redux