无限循环与 redux-saga [英] Infinite loop with redux-saga

查看:18
本文介绍了无限循环与 redux-saga的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用 react-router v4 和 redux-saga.我正在尝试在页面加载时进行 API 调用.当我访问 /detailpage/slug/ 时,我的应用程序似乎陷入了一个循环,并对我的 API 端点进行了无休止的调用.这是我的应用程序的设置方式.假设我的导入是正确的.

I'm using react-router v4 and redux-saga. I'm attempting to make an API call when a page loads. When I visit /detailpage/slug/, my application seems to get stuck in a loop and makes endless calls to my API endpoint. Here's how my application is setup. Assume my imports are correct.

index.js

const history = createHistory()
const sagaMiddleware = createSagaMiddleware()
const middleware = [routerMiddleware(history), sagaMiddleware]

const store = createStore(
  combineReducers({
    aReducer
  }),
  applyMiddleware(...middleware)
)

injectTapEventPlugin();
sagaMiddleware.run(rootSaga)


ReactDOM.render(
  <Provider store={store}>
  <ConnectedRouter history={history}>
    <Switch>
      <Route path="/" exact component={HomePage} />
      <Route path="/detailpage/:slug" component={Detail} />
      <Route path="/page" component={Page} />
    </Switch>
  </ConnectedRouter>
  </Provider>,
  document.getElementById('root')
);

reducers/index.js

const aReducer = (state={}, action) => {
  switch(action.type) {
    case 'SHOW_DETAIL':
    console.log('Reducers: reducer called')
    return Object.assign({}, state, { name: 'adfsdf' })
  default:
    return state;
  }
}
export default aReducer;

actions/index.js

export const showDetailInfo = () => {
  console.log('action called')
  return {
    type: 'SHOW_DETAIL'
  }
}

saga.js

export function* fetchDetailsAsync() {
  try {
    console.log('fetching detail info')
    const response = yield call(fetch, 'http://localhost:8000/object/1/', {
    method: 'GET',
    headers: {
      'Authorization': 'Token xxxxxxxxxxxx'
    }})

    console.log(response);

    yield put({type: 'SHOW_DETAIL', response: response.data})
  } catch (e) {
    console.log('error')
  }
}

// watcher saga
export function* fetchDetails() {
  console.log('watcher saga')
  yield takeEvery('SHOW_DETAIL', fetchDetailsAsync)
}

export default function* rootSaga() {
  console.log('root saga')
  yield [
    fetchDetails()
  ]
}

容器/Detail.js

const mapStateToProps = (state) => {
  return {
    name: 'Test'
  }
}

const mapDispatchToProps = (dispatch, ownProps) => {
  console.log('mapDispatchToProps')
  return {
    showDetailInfo: (payload) => {
      console.log('dispatching');
      dispatch({ type: 'SHOW_DETAIL' })
    }
  }
}

const Detail = connect(
  mapStateToProps,
  mapDispatchToProps
)(DetailPage)

export default Detail;

components/DetailPage.js

class DetailPage extends React.Component {

  componentWillMount() {
    this.props.showDetailInfo();
  }

  render() {
    return (
      <Layout>
      <h3>DetailPage</h3>
      <p>{ this.props.name }</p>
      </Layout>
    )
  }
}

DetailPage.PropTypes = {
  showDetailInfo: PropTypes.func.isRequired,
  name: PropTypes.string.isRequired
}

export default DetailPage;

我花了几天时间进行故障排除,尝试了各种想法,包括测试不同的生命周期方法、从 applyMiddleware 中删除 routerMiddleware.

I've spent a few days troubleshooting, trying various ideas including testing different lifecycle methods, removing the routerMiddleware from applyMiddleware.

我认为我的组件在每次 API 调用后都会更新,但任何生命周期方法的 console.log 都表明它不是.

I thought that my component was updating after every API call, but console.log from any of the lifecycle methods indicates that it's not.

作为 React 生态系统的新手,这里有很多活动部分,对我来说排查问题很有挑战性.

Being new to react ecosystem, there are a lot of moving parts here and it's challenging for me to troubleshoot.

推荐答案

当然,你在下几行明确设置了无限循环:

Of course, you explicitly set the infinite loop the next lines:

yield put({type: 'SHOW_DETAIL', response: response.data})
// ...
yield takeEvery('SHOW_DETAIL', fetchDetailsAsync)

saga 不会为您做任何神奇的事情,它只是订阅和生成操作和执行协程的初级层.

The saga doesn't do any magic things for you, and only is a preliminary layer of a subscription and generation on actions and executions coroutines.

解决方案:

对于从 React 组件捕获的操作,以及用于乐观和真实更新状态的操作,您应该使用不同的名称.

You shall use different names for actions which you catch from React components, and actions which are used for optimistical and real up-dating of a status.

使用 yield takeEvery('SHOW_DETAIL_REQUEST', fetchDetailsAsync) 并以此方式命名您的操作.

Use yield takeEvery('SHOW_DETAIL_REQUEST', fetchDetailsAsync) and name your action in this manner.

在成功响应中使用 yield put({type: 'SHOW_DETAIL_SUCCESS', response: response.data}) 并以这种方式命名您的减速器

Use yield put({type: 'SHOW_DETAIL_SUCCESS', response: response.data}) in success response and name your reducer in this manner

不仅如此,您还可以使用 'SHOW_DETAIL_FAILURE' 来处理失败的 saga 请求.

More than that, you can use 'SHOW_DETAIL_FAILURE' for failed saga request.

以上所有名称均为常用大小写.

All names above are common-used case.

这篇关于无限循环与 redux-saga的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆