首页 > 解决方案 > 在路由加载时将模型加载到 redux 存储的最佳方法

问题描述

我有一个 React 应用程序,它使用 React-Router/React-Router-dom 进行页面导航和 redux 来存储一些全局状态信息(例如 django rest 框架的 jwt 令牌)。该状态还存储有关当前查看页面的信息,例如序列化的 django 模型。

但是当路由发生变化时,将 django 模型加载到 redux 存储中的最佳方法是什么?我在思考逻辑应该去哪里时遇到了麻烦。

如果您查看下面的 repo,您​​可以看到我在哪里无法弄清楚。

在此示例中,当有人导航到 时/spells/:id,它应该将spelldjango 模型加载到 redux 存储中,以便全局可访问有关它的信息。

但是我该怎么做呢?我在哪里调用动作和减速器来正确处理状态?

任何指导将不胜感激。

您可以在此处查看完整的项目。这里讨论的组件是LayoutSpellView( /frontend/src/components/LayoutSpellView)。那是存储、显示模型信息等的地方。

编辑:添加相关代码

调用componentDidMount

axios
    .get("http://localhost:3000/api/spells/" + spellId)
    .then(response => {
        let spell = Object.assign({}, spellView.state.spell);

        spell.id =  response.data.id;
        spell.owner =  response.data.owner;
        ...blahblah other fields

        this.setState({
            spell
        });


    })
    .then(response => {
        this.props.dispatch({
            type: 'FETCH_SPELL_SUCCESS',
            payload: this.state.spell,
        });
    })
    .catch(function(error) {
        console.error('[API]\t', error);
    });

LayoutSpellView(与上述相同的组件)

import {loadSpell} from "../src/reducers";
const mapStateToProps = (state) => ({
    spell: loadSpell(state.spell.id),
});
const mapDispatchToProps = (dispatch) => ({
    getSpell: (state.spell.id) => {
        dispatch(loadSpell(state.spell.id))
    }
});

动作拼写.js:

export const FETCH_SPELL = '@@spell/FETCH_SPELL';
export const FETCH_SPELL_SUCCESS = '@@spell/FETCH_SPELL_SUCCESS';
export const FETCH_SPELL_FAILURE = '@@spell/FETCH_SPELL_FAILURE';

export const loadSpell = (spellId) => ({
    [RSAA]: {
        endpoint: '/api/spell/${spellId}',
        method: 'GET',
        types: [
            FETCH_SPELL, FETCH_SPELL_SUCCESS, FETCH_SPELL_FAILURE
        ]
    }
});

减速器 spell.js:

const initialState = {
    spell: {
        id: 0,
        owner: 0,
        Name: 'Name',
        School: 'unknown',
        Subschool: 'unknown',
    }
};
export default (state=initialState, action) => {
    switch(action.type) {
        case spell_action.FETCH_SPELL_SUCCESS:
            return {
                spell: {
                    id: action.payload.spell.id,
                    owner: action.payload.spell.owner,
                    Name: action.payload.spell.Name,
                    School: action.payload.spell.School,
                    Subschool: action.payload.spell.Subschool,
                }
            };
        default:
            return state;
    }
}

export function loadSpell(state) {
    if (state) {
        return state.spell
    }
}

标签: reactjsreduxdjango-rest-frameworkreact-routerjwt

解决方案


让我们换个角度来看这个问题。与其问“当路由改变时我如何调度一个动作”,不如问“什么是真实的真实来源:Redux 还是 URL?”

如果我们选择redux成为单一事实来源,那么这意味着我们需要dispatch一些action会导致一些副作用(可能redux-sagaredux-observable什至redux-thunk?)的东西,从而改变了 url:

Comp -> dispatch(action) -> store updates -> URL changes

如果我们将 URL 作为单一事实来源,我们将流程更改为:

URL changes -> dispatch(action) -> store updates

如果我们走这条路,这听起来像你想要的,你可能需要 hook up middleware,这是以下签名的函数:

store => next => action => next(action)

根据您使用的路由器,您可以挂钩他们的操作,也可以挂钩window.onpopstate并检查下一个 url。无论哪种方式,整个中间件功能看起来像

const middleware = store => {
  return next => action => {
    if (actionWillCauseSpellToBeNeeded(action)) {
       makeAPICall()
         .then(transformAPIToAction)
         .catch(transformError)
         .then(store.dispatch) 
    }
    return next(action)
  }
}

推荐阅读