繁体   English   中英

使用Redux Saga更新单个状态属性的最佳实践

[英]Best practice for updating individual state properties with Redux Saga

所以我正在使用Redux Saga在React中实现一个应用程序,我对我的特定用例的信息很少感到困惑,因为它看起来并不奇怪。 很可能我使用了错误的术语或以错误的方式思考问题,因为我对React / Redux很新。 在任何情况下,我都被我试图谷歌这个问题所困扰,并且会感谢来自框架中比我更有经验的人的一些见解。

我的应用程序状态上有一个userSettings属性,用于管理登录用户的一些配置选项。 在应用程序的某一点上,用户可以翻转开关以禁用“一目了然”仪表板小部件的显示,我需要将此信息传递给后端API以更新其在数据库中的设置信息,然后根据此后端更新是否成功更新状态。

我目前的代码对于所有用户设置更新都有一个主要的传奇,我打算通过特定的更具体的传奇来达到这一点,因此:

Dashboard.js

function mapStateToProps(state) {
    const { userSettings } = state;
    return { userSettings };
}
...
class Dashboard extends Component {
    ...
    ...
    hasDashboardAtAGlanceHiddenToggle() {
        const { dispatch, userSettings } = this.props;
        dispatch(setHasDashboardAtAGlanceHidden(!userSettings.hasDashboardAtAGlanceHidden));
    }
}
export default connect(mapStateToProps)(Dashboard);

updateUserSettingsSaga.js

import { take, put, call } from 'redux-saga/effects';
import axios from 'axios';

import {
    UPDATE_USER_SETTINGS,
    SET_HAS_DASHBOARD_AT_A_GLANCE_HIDDEN,
    updateUserSettings,
    updatedUserSettingsSuccess
} from '../../actions';

export function* setHasDashboardAtAGlanceHiddenSaga() {
    const action = yield take(SET_HAS_DASHBOARD_AT_A_GLANCE_HIDDEN);
    const newValue = action.data;
    //QUESTION HERE -- how to get full object to pass to updateUserSettings
    yield put(updateUserSettings(stateObjectWithNewValuePopulated));
}

export default function* updateUserSettingsSaga(data) {
    yield take(UPDATE_USER_SETTINGS);
    try {
        const response = yield call(axios.put, 'http://localhost:3001/settings', data);
        yield put(updatedUserSettingsSuccess(response.data));
    } catch (e) {
        yield put(updatedUserSettingsFailure());
    }
}

正如代码中所提到的,我的问题是,我不确定将更新后的值合并到状态的逻辑应该在何处/如何发生。 尽可能接近,我有三个选择:

  1. 在分派初始操作之前在组件中构建更新状态,即:

     hasDashboardAtAGlanceHiddenToggle() { const { dispatch, userSettings } = this.props; const newState = Object.assign({}, userSettings , { hasDashboardAtAGlanceHidden: !userSettings.hasDashboardAtAGlanceHidden }); dispatch(setHasDashboardAtAGlanceHidden(userSettings)); } 

    }

  2. 使用redux-saga的select效果并在更具体的初始传奇中构建完整的状态对象,即:

     export function* setHasDashboardAtAGlanceHiddenSaga() { const action = yield take(SET_HAS_DASHBOARD_AT_A_GLANCE_HIDDEN); const newValue = action.data; const existingState = select(state => state.userSettings); const updatedState = Object.assign({}, existingState, { hasDashboardAtAGlanceHidden: newValue }); yield put(updateUserSettings(updatedState)); } 
  3. 在更新之前检索服务器的用户设置对象副本,即:

     export default function* updateUserSettingsSaga() { const action = yield take(UPDATE_USER_SETTINGS); try { const current = yield call(axios.get, 'http://localhost:3001/settings'); const newState = Object.assign({}, current.data, action.data); const response = yield call(axios.put, 'http://localhost:3001/settings', newState); yield put(updatedUserSettingsSuccess(response.data)); } catch (e) { yield put(updatedUserSettingsFailure()); } } 

所有这些(我认为)都可以作为选项,但我不清楚在Redux Saga的背景下哪个是惯用的/接受的/可取的方法,并且有一个令人眼花缭乱的缺乏例子(至少那个我已经能够找到)在与外部API接口时使用POST / PUT而不是GET。 任何帮助或指导都会受到赞赏 - 即使只是因为我正在以错误的方式思考这个问题。 :d

GET/PUT/POST方面与问题无关。 总的来说,您的问题实际上归结为常见问题“如何在动作创建者和减少者之间分离逻辑?” 引用那个答案:

对于减速器或动作创建者应该采用什么样的逻辑,没有一个明确的答案。 一些开发人员更喜欢拥有“胖”动作创建器,其中“瘦”缩减器只是简单地将动作中的数据接收并盲目地将其合并到相应的状态中。 其他人试图强调保持尽可能小的动作,并最小化动作创建者中getState()的使用。 (出于这个问题的目的,其他异步方法,如sagas和observables属于“行动创造者”类别。)

将更多逻辑放入减速机有一些潜在的好处。 动作类型可能更具语义性和更有意义(例如“USER_UPDATED”而不是“SET_STATE”)。 此外,在reducer中使用更多逻辑意味着更多功能将受到时间旅行调试的影响。

这个评论很好地总结了二分法:

现在,问题是在动作创建器中放置什么以及在reducer中放置什么,在fat和thin动作对象之间进行选择。 如果将所有逻辑放在动作创建器中,最终会生成基本上声明状态更新的胖动作对象。 Reducers变得纯粹,愚蠢,添加 - 删除它,更新这些功能。 它们很容易构成。 但是你的业务逻辑并不多。 如果你在reducer中加入了更多的逻辑,你最终会得到漂亮的瘦动作对象,大部分数据逻辑都集中在一个地方,但是你的reducer更难以编写,因为你可能需要来自其他分支的信息。 你最终得到了大型减速器或减速器,它们从该州的较高位置获取额外的参数。

我不久前还写了一篇关于“厚薄的减速器”想法

所以,最终这是你喜欢如何构建逻辑的问题。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM