调度执行AJAX请求的动作时的无限循环 - ReactJS,Redux,Redux-saga

Ron*_*eon 3 ajax reactjs redux redux-saga react-redux

我正在尝试使用redux-saga和axios加载组件的数据,但我一直在获得无限循环.这些是相关的组成部分:

App.js

class App extends React.Component {
  render() {
    return (
      <div className="app">
        <header>
          <div className="pure-u-1 pure-u-sm-1-3">

          </div>
          <nav className="pure-u-1 pure-u-sm-2-3">
            <ul>
              <li><Link to="/meal-plans">Meal Plans</Link></li>
            </ul>
          </nav>
        </header>
        <main>
          <div className="view-area">
            <Switch>
              <Route exact path="/" component={() => <DashBoard {...this.props} />} />
              <Route exact path="/meal-plans" component={() => <MealPlansContainer {...this.props} />} />
              <Route path="/meal-plans/:id" component={props => <MealPlan {...this.props} {...props} />} />
            </Switch>
          </div>
        </main>
      </div>
    )
  }
}

function mapStateToProps(state) {
  return {
    app: state.app,
    mealPlan: state.mealPlan,
    mealPlans: state.mealPlans,
  }
}

function mapDispatchToProps(dispatch) {
  return bindActionCreators(actionCreators, dispatch);
}

App = withRouter(connect(mapStateToProps, mapDispatchToProps)(App));

export default App;
Run Code Online (Sandbox Code Playgroud)

MealPlan.js

class MealPlan extends React.Component {
    componentDidMount() {
        let id = this.props.match.params.id
        this.props.fetchMealPlan(id);
    }
    render() {
        return (
            <div className="meal-plan pure-g box">
                <div className="pure-u-1">
                    <p>Future Meal Plan Page</p>
                    <LoadingSpinner show={true} />
                </div>
            </div>
        );
    }
}
Run Code Online (Sandbox Code Playgroud)

我是React的新手,我对组件生命周期没有很好的把握,但我相信每次AJAX请求完成时都会调用componentDidMount(),并且在reducer中运行'FETCH_MEAL_PLAN_SUCCESSFUL'.

actionCreators.js

export function fetchMealPlan(id) {
  return {
    type: 'FETCH_MEAL_PLAN',
    id
  }
}

export function fetchMealPlanSuccessful(data) {
  return {
    type: 'FETCH_MEAL_PLAN_SUCCESSFUL',
    data
  }
}

export function fetchMealPlanFail(message) {
  return {
    type: 'FETCH_MEAL_PLAN_FAIL',
    message
  }
}
Run Code Online (Sandbox Code Playgroud)

sagas.js

function* fetchMealPlan(action) {
  try {
    const mealPlan = yield call(api.get, '/meal_plans/' + action.id);
    yield put(fetchMealPlanSuccessful(mealPlan.data));
  } catch (e) {
    yield put(fetchMealPlanFail(e.message));
  }
}

function* watchFetchMealPlan() {
  yield takeLatest('FETCH_MEAL_PLAN', fetchMealPlan);
}
Run Code Online (Sandbox Code Playgroud)

mealPlan.js(减速机)

function mealPlan(state = {}, action) {
  switch(action.type) {
    case 'FETCH_MEAL_PLAN':
      return state;
    case 'FETCH_MEAL_PLAN_FAIL':
      return state;
    case 'FETCH_MEAL_PLAN_SUCCESSFUL':
      state = Object.assign({}, action.data);
      return state;
      break;
    default:
      return state;
  }
}

export default mealPlan;
Run Code Online (Sandbox Code Playgroud)

如果我不停止该应用程序,它将继续提出请求.在这个测试中,它产生了4,200多个请求: App无限循环

我花了几个小时研究如何在更改路径后最好地从我的API中为组件加载数据,到目前为止我还没有成功.预先感谢您的帮助.

Che*_*glu 5

通常,组件应该运行componentDidMount一次,除非它被解除分配然后再次安装.如果它的道具或状态发生变化,那么componentDidUpdate就会被解雇.

因此,如果您遇到多个componentDidMount,那么这个组件很可能嵌套为一个孩子(我猜你是从你的代码片段中做到的),然后当它的父级(App)状态或道具改变时,它会重新渲染它的孩子(包括MealPlan).由于要连接mealPlanmealPlan从终极版到App.每当你调用API时,App的道具都会被更新,从而导致其子项被重新渲染,并componentDidMount一次又一次地导致MealPlan触发.

我不是React的超级经验.但我还没有看到你设置路线的方式.一种方法是在单独的文件中定义路由器,并使用这样的路由器(这使用react-router的代码分割功能):

const router = (
  <Router history={browserHistory}>
    <Route path="/" component={App}>
     <Route path="/meal-plans" component={MealPlan} />
    </Route>
  </Router>
)

ReactDOM.render(
    <Provider store={createStoreWithMiddleware(reducers)}> // react-redux provider
      { router }
    </Provider>,
  document.querySelector('#main'));
Run Code Online (Sandbox Code Playgroud)

如果你想进行代码分割,因为你使用的是redux-sagas,一个好的模板是https://github.com/react-boilerplate/react-boilerplate.通过研究他们如何做到这一点,你可以实现你想要的

  • 将我的'MealPlan`组件连接到redux而不是`App`解决了我的问题.我花了这么多时间研究和挣扎,感谢你的帮助! (2认同)