如何在useEffect

时间:2020-04-06 20:11:57

标签: javascript reactjs react-redux

我目前正在学习React / hooks / redux。为此,我正在构建一个从气候API接收数据的react应用。

我遇到的问题是正确设置useEffect中的几个项目的状态。一种状态依赖于另一种状态,因此我试图找出如何正确调用useEffect的方法,这样就不会出现无限循环并遵循最佳实践。

下面的代码之前有一点背景:

-用户创建一个项目,然后选择一个城市。这将产生一个cityId,我将其存储在“项目”状态下。

-在用户的仪表板上,他们可以单击一个项目,该项目将queryString中的项目ID发送到我的ClimateData组件。

-ClimateData将项目ID queryString传递到“ getProjectByID” redux操作以获取项目状态,包括城市ID。

-ClimateData包含IndicatorList组件,该组件会列出所有气候数据突破的列表。我希望用户单击这些列表项之一,并设置ClimateData的“ indicatorByCityData”状态。因此,我将ClimateData的setState函数传递给了IndicatorList,并使用onClicks进行了列表调用。 是否有更好的方法?

-在ClimateData上,一旦有了项目的cityId和从IndicatorList中选择的项目,我就需要调用“ getIndicatorByCity”并传递cityId和indicator以将结果保存在“ indicatorByCityData”状态

我一直在尝试更改ClimateData的useEffect的编写方式,但是我遇到了无限循环或错误。我怎样才能最好地更改此设置以设置两种状态并遵循最佳做法?

redux动作和减速器已经在其他地方进行了测试,并且可以正常工作,因此,为了简洁起见,在此将它们排除在外,而只关注我的ClimateData和IndicatorList组件:

import React, { Fragment, useState, useEffect } from 'react';
import { Link } from 'react-router-dom';
import { connect } from 'react-redux';
import PropTypes from 'prop-types';
import IndicatorList from './IndicatorList';
import Spinner from '../layout/Spinner';
import { getProjectById } from '../../actions/projects';
import { getIndicatorByCity } from '../../actions/climate';

const ClimateData = ({
  getProjectById,
  getIndicatorByCity,
  project: { project, loading },
  auth,
  match
}) => {
  const [indicatorByCityData, setIndicatorByCityData] = useState({});

  const nullProject = !project;
  useEffect(() => {
    if (!project) getProjectById(match.params.id);

    // Once we have the cityID, set the indicatorByCityData state, with a default selected Indicator
    if (!loading) setIndicatorByCityData(getIndicatorByCity(project.cityId));
  }, []);

  // Get the selected indicator from IndicatorList and update the indicatorByCityData state
  const setIndicator = indicator => {
    setIndicatorByCityData(getIndicatorByCity(project.cityId, null, indicator));
  };

  return (
    <Fragment>
      {project === null || loading || !indicatorByCityData ? (
        <Spinner />
      ) : (
        <Fragment>
          <Link to='/dashboard' className='btn btn-light'>
            Back To Dashboard
          </Link>

          <h1 className='large text-primary'>{`Climate Data for ${project.city}`}</h1>
          <IndicatorList setIndicator={setIndicator} />
        </Fragment>
      )}
    </Fragment>
  );
};

ClimateData.propTypes = {
  getProjectById: PropTypes.func.isRequired,
  getIndicatorByCity: PropTypes.func.isRequired,
  project: PropTypes.object.isRequired,
  auth: PropTypes.object.isRequired
};

const mapStateToProps = state => ({
  project: state.projects,
  auth: state.auth
});

export default connect(mapStateToProps, { getProjectById, getIndicatorByCity })(
  ClimateData
);

/******************************************************************/

import React, { useEffect, Fragment } from 'react';
import { connect } from 'react-redux';
import PropTypes from 'prop-types';
import Spinner from '../layout/Spinner';
import { getIndicatorList } from '../../actions/climate';

const IndicatorList = ({
  getIndicatorList,
  auth: { user },
  climateList: { indicatorList, loading },
  setIndicator
}) => {
  useEffect(() => {
    getIndicatorList();
  }, [getIndicatorList]);

  return loading ? (
    <Spinner />
  ) : (
    <Fragment>
      {indicatorList.length > 0 ? (
        <Fragment>
          <ul>
            {indicatorList.map(indicator => (
              <li key={indicator.name}>
                <a href='#!' onClick={() => setIndicator(indicator.name)}>
                  {indicator.label}
                </a>
                <br />- {indicator.description}
              </li>
            ))}
          </ul>
        </Fragment>
      ) : (
        <h4>No climate indicators loaded</h4>
      )}
    </Fragment>
  );
};

IndicatorList.propTypes = {
  auth: PropTypes.object.isRequired,
  climateList: PropTypes.object.isRequired,
  setIndicator: PropTypes.func.isRequired
};

const mapStateToProps = state => ({
  auth: state.auth,
  climateList: state.climate
});
export default connect(mapStateToProps, { getIndicatorList })(IndicatorList);

0 个答案:

没有答案