反应条件渲染会导致多个api调用

时间:2018-12-05 05:35:05

标签: reactjs react-redux redux-saga

我正在使用React + Redux + Redux-Saga。

在我的情况下,我正在调用2个api-用于Config和用于Data(在提取Config之后)

调用数据时出现问题。简而言之:

这有效:

TestRoute.jsx文件(尚未使用isConfig):

import React from 'react';
import { connect } from 'react-redux';
import TestComponent from '../components/Test';

const Test = ({ isConfig }) => <div>
  <TestComponent />
  <TestComponent />
  <TestComponent />
  <TestComponent />
</div>

const mapStateToProps = state => ({
  isConfig: !!state.config.payload.tenantId
});

export default connect(mapStateToProps)(Test);

TestComponent.jsx

import React, { Component } from 'react';
import { connect } from 'react-redux';
import { dataRequestInit } from '../state/actions/data';

class Test extends Component {
  componentDidMount() {
    this.props.dataRequestInit('https://data/api/url');
  }

  render() {
    return <p>hello</p>;
  }
}

const mapStateToProps = state => ({})

export default connect(
  mapStateToProps,
  { dataRequestInit }
)(Test);

Saga文件:

const getIsFetching = (state, url) => state.data.isFetching.includes(url);

function* fetchData(url) {
  try {
    const isFetching = yield select(getIsFetching, url);

    if (!isFetching) {
      yield put(actions.fetchDataIsFetching(url));

      const response = yield call(api, url);

      console.log('response', response);
    }
  } catch (err) {
    console.log('handle error', err);
  }
}

export default function* DataSaga() {
  yield takeEvery(actionTypes.FETCH_DATA_INIT, fetchData);
}

在这种情况下,一切都很好-第一个调用设置为isFetching,并且正在执行一个api请求。 Redux DevTools view

但是如果我重新创建Route文件以开始使用isConfig标志并有条件地渲染TestComponents:

const Test = ({ isConfig }) =>
  isConfig && (
    <div>
      <TestComponent />
      <TestComponent />
      <TestComponent />
      <TestComponent />
    </div>
  );

一切都变得疯狂,并且向服务器发送了4个api调用。那是因为开始Redux DevTools view而不是像预期的那样,先启动4x DATA / FETCH_INIT动作,然后再执行4x DATA / SET_IS_FETCHING动作:1x DATA / FETCH_INIT 1x DATA / SET_IS_FETCHING 3x DATA / FETCH_INIT像以前一样。

有人可以向我解释为什么会这样吗?我在这里缺少什么,以及可能如何解决该问题?

1 个答案:

答案 0 :(得分:0)

我可以看到您的问题,您将同一组件安装了4次,如下所示:

componentDidMount() {
  this.props.dataRequestInit('https://data/api/url');
}

然后渲染4次:

  <TestComponent />
  <TestComponent />
  <TestComponent />
  <TestComponent />

这将为每个组件触发一个单独的函数调用实例,具有用于“ isFetching”的变量不会阻止其他组件进行API调用。

还要注意的另一件事是,如果此组件需要渲染4次,并且它们都需要相同的数据,则最好将控制权交给父组件,一次获取数据,然后将其传递给每个实例中的组件,如下所示:

<TestComponent data={state.data}/>

此外,此操作的减速器情况应如下所示:

switch (action.type) {
  case AUTH_REQUEST:
    return {
      ...state
    }

具有传播运算符的状态变量,它使状态保持先前的操作,在您的情况下为获取变量。

希望这会有所帮助

劳埃德