【问题标题】:Node/React/Redux: having problems passing api JSON object between Node and ReactNode/React/Redux:在 Node 和 React 之间传递 api JSON 对象时遇到问题
【发布时间】: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

在此先感谢您的帮助。

***** 更新 *****

  1. 我注意到我在客户端的 actions/weather.js 和 reducers/weather.js 以及服务器端的 routes/api/weather.js 中的控制台日志都没有触发。这告诉我这些模块一定不能执行。这可以解释为什么我在 client/src/components/pages/functional/Weather.js 中收到错误“无法读取未定义的属性‘当前’”。显然,我在这个链条中缺少一个环节。我只是看不到它是什么。

  2. 我尝试了一个小的重构,基于下面的输入。我试图查看是否存在某种命名冲突。这就是我在我的 React 功能组件中所做的:

// client/src/components/pages/functional/Weather.js

...

const mapStateToProps = state => ({weather: { forecast: state.forecast, loading: state.loading }});

...

没用。

【问题讨论】:

    标签: node.js reactjs redux react-redux


    【解决方案1】:

    你需要修改你的组件。

    const dispatch = useDispatch();
    
    useEffect(() => { dispatch(getWeather()); }, [getWeather])
    

    您的mapToStateToProps 应该如下:

    const mapStateToProps = state => ({ forecast: state.weather.forecast });
    

    【讨论】:

      【解决方案2】:

      我看到你在 combineReducers here 中设置为

      export default combineReducers({
        alert,
        auth,
        weather
      

      })

      所以在商店里,东西被保存为{ alert: {...}, auth: {...}, weather: {...}}。您可以尝试以state.weather.forecast 的形式访问Weather 中的预测值吗?

      const mapStateToProps = state => ({ forecast: state.weather.forecast });
      

      让我知道它是否有效。

      【讨论】:

      • 我会尝试并告诉你。
      • 我尝试过并对其进行了修改。都没有奏效。但感谢您的意见。
      猜你喜欢
      • 2019-02-18
      • 2017-11-03
      • 1970-01-01
      • 2016-12-09
      • 2019-07-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多