React、Redux、NextJS 奇怪的状态竞争覆盖

React, Redux, NextJS Weird state race overrides

我有一个带有 2 个减速器的应用程序(城市和医生) 我用传奇。 我有一个奇怪的状态覆盖的问题。

例如这里是fetch doctors动作的开始。如您所见,医生 isLoading: false 的状态已更改为 isLoading: true

在那之后,获取城市的行动就在之前开始了。医生的 isLoading 改回 false

在每个动作调度中,另一个 reducer 状态重置。

我怀疑这是 NextJS 的特定问题,因此根存储创建了几次并导致竞争条件。

技术:react、redux、react-redux、next-redux-wrapper、next-redux-saga、redux-saga

app.js

....
export default withRedux(createStore)(withReduxSaga(MyApp))

store.js

import { applyMiddleware, createStore } from 'redux'
import createSagaMiddleware from 'redux-saga'

import rootReducer from './rootReducer'
import rootSaga from './rootSaga'


const bindMiddleware = middleware => {
  if (process.env.NODE_ENV !== 'production') {
    const { composeWithDevTools } = require('redux-devtools-extension')
    return composeWithDevTools(applyMiddleware(...middleware))
  }
  return applyMiddleware(...middleware)
}


function configureStore(initial={}) {
  const sagaMiddleware = createSagaMiddleware()
  const store = createStore(
    rootReducer,
    initial,
    bindMiddleware([sagaMiddleware])
  )

  store.sagaTask = sagaMiddleware.run(rootSaga)

  return store
}

export default configureStore

rootReducer.js

import { combineReducers } from 'redux'
import { cityReducer } from "./reducers/city"
import { doctorReducer } from "./reducers/doctor"

export default combineReducers({
  city: cityReducer,
  doctor: doctorReducer
})

city/reducer.js

import {actionTypes} from "../../actions/city"

const initialState = {
  cities: []
}

export const cityReducer = (state = initialState, action) => {
  switch (action.type) {
    case actionTypes.FETCH_CITIES:
      return initialState
    case actionTypes.FETCH_CITIES_SUCCESS:
      return {
        cities: action.data
      }
    case actionTypes.FETCH_CITIES_FAILURE:
      return initialState
    default:
      return initialState
  }
}

city/actions.js

export const actionTypes = {
  FETCH_CITIES: 'FETCH_CITIES',
  FETCH_CITIES_SUCCESS: 'FETCH_CITIES_SUCCESS',
  FETCH_CITIES_FAILURE: 'FETCH_CITIES_FAILURE',
}

export const fetchCities = () => {
  return {
    type: actionTypes.FETCH_CITIES
  }
}
export const fetchCitiesSuccess = (data) => {
  return {
    type: actionTypes.FETCH_CITIES_SUCCESS,
    data
  }
}
export const fetchCitiesFailure = () => {
  return {
    type: actionTypes.FETCH_CITIES_FAILURE
  }
}

city/saga.js

import {call, put, takeLatest} from "redux-saga/effects"
import {actionTypes, fetchCitiesFailure, fetchCitiesSuccess} from "../../actions/city"
import {getCities} from "../../api"


export function* watchFetchCitiesRequest() {
  yield takeLatest(actionTypes.FETCH_CITIES, workerFetchCitiesRequest)
}

function* workerFetchCitiesRequest() {
  try {
    const {data} = yield call(getCities)

    yield put(fetchCitiesSuccess(data.results))
  } catch (e) {
    yield put(fetchCitiesFailure())
  }
}

(!) 对于医生来说 reducer/saga/actions 除了名字之外结构是一样的。

Page.js 是每个页面的主要布局。 基本上把每一页的内容都包裹在_document.js

const Page = ({dispatch}) => {
  useEffect(() => {
    dispatch(fetchCities())
  }, [])
} 
const mapStateToProps = ({city}) => ({cities: city.cities})
export default connect(mapStateToProps)(Page)

DoctorList.js /doctor page 使用的组件

import {useEffect} from "react"
import {fetchDoctors} from "../../actions/doctor"
import {getCity} from "../../utils/functions"
import {DoctorItemPreview} from "./DoctorItem"

const DoctorList = ({dispatch, isLoading, isError, response}) => {

  useEffect(() => {
    getCity() ? dispatch(fetchDoctors()) : null
  },[getCity()])
  return <>
    {!isLoading ? <>

    </> : <>
      {[...Array(10)].map((e, i) => <span key={i}>
        <DoctorItemPreview/>
      </span>)}
    </>}
  </>
}

const mapStateToProps = ({doctor, city}) => ({
  isLoading: doctor.isLoading,
  isError: doctor.isError,
  response: doctor.response,
})
export default connect(mapStateToProps)(DoctorList)

问题出现的地方可能是什么?您需要哪些代码部分才能得到答案?谢谢

我很确定你的减速器在返回 initialState 时会覆盖你当前的 state。看到这个 answer on GitHub.

next-redux-saga.

中没有已知的竞争条件或与多个根存储或缩减器相关的其他问题