reactjs - 在路由加载时将模型加载到 redux 存储的最佳方法
问题描述
我有一个 React 应用程序,它使用 React-Router/React-Router-dom 进行页面导航和 redux 来存储一些全局状态信息(例如 django rest 框架的 jwt 令牌)。该状态还存储有关当前查看页面的信息,例如序列化的 django 模型。
但是当路由发生变化时,将 django 模型加载到 redux 存储中的最佳方法是什么?我在思考逻辑应该去哪里时遇到了麻烦。
如果您查看下面的 repo,您可以看到我在哪里无法弄清楚。
在此示例中,当有人导航到 时/spells/:id
,它应该将spell
django 模型加载到 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
}
}
解决方案
让我们换个角度来看这个问题。与其问“当路由改变时我如何调度一个动作”,不如问“什么是真实的真实来源:Redux 还是 URL?”
如果我们选择redux
成为单一事实来源,那么这意味着我们需要dispatch
一些action
会导致一些副作用(可能redux-saga
或redux-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)
}
}
推荐阅读
- angular - 角度6反应形式FormGroup验证
- redis - Redis在线数据结构从set到zset的变化
- swift - swift 4 是否需要一个主类来运行?我什么时候应该使用一个类来运行我的代码?
- java - 无法获取 stax2 java 包的版本
- database - 我们称链接任何其他两个表的表是什么?
- reactjs - React - 警告:使用 `defaultValue` 或 `value` 道具
- abap - 从动态分配的结构中创建
- mysql - 为什么使用 laravel 框架运行迁移后找不到新表?
- mysql - Laravel Eloquent 在一个查询中使用不同条件进行多次计数
- javascript - 在 textarea 中包含换行符作为 maxlength 一部分的最佳方法是什么