在路由加载时将模型加载到 redux 存储的最佳方法
Posted
技术标签:
【中文标题】在路由加载时将模型加载到 redux 存储的最佳方法【英文标题】:Best Way to load model into redux store on route load 【发布时间】:2018-12-19 03:43:56 【问题描述】:我有一个 React 应用程序,它使用 React-Router/React-Router-dom 进行页面导航和 redux 来存储一些全局状态信息(例如 django rest 框架的 jwt 令牌)。该状态还存储有关当前查看的页面的信息,例如序列化的 django 模型。
但是当路由发生变化时,将 django 模型加载到 redux 存储中的最佳方法是什么?我在思考逻辑应该走向何方时遇到了麻烦。
如果您查看下面的 repo,您会发现我在哪里遇到了麻烦。
在此示例中,当有人导航到 /spells/:id
时,它应该将 spell
django 模型加载到 redux 存储中,以便全局可访问有关它的信息。
但是我该怎么做呢?我在哪里调用 action 和 reducer 来正确处理状态?
任何指导将不胜感激。
您可以查看完整的项目here。这里有问题的组件是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))
);
动作 spell.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
【问题讨论】:
我可能会在组件的componentDidMount
中调用一个操作来检索/存储数据。
@NorianNyx 我想了这么多。这实际上是我有一个 axios 调用来检索它的地方。但是在哪里以及如何调用操作以从本地以外的地方推送新状态?
您可以在您的 axios 调用的 .then
方法中调用它,例如:this.props.dispatch( type: 'RETRIEVE_SUCCESS', payload: res.data )
(或任何您的调度操作模式)。然后在你的减速器中:case 'RETRIEVE_SUCCESS': (state, action) => ( ...state, action.payload )
@NorianNyx 我想我做到了,但它不断给我错误,它是未定义的。我在我的问题中添加了相关的代码。我做得对吗?
负载是否未定义?
【参考方案1】:
让我们换个角度来看这个问题。与其问“当路由改变时我如何调度一个动作”,不如问“什么是真实的真实来源: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
如果我们走这条路,这听起来像你想要的,你可能需要连接middleware
,这是以下签名的函数:
store => next => action => next(action)
根据您使用的路由器,您可以挂钩他们的操作,也可以挂钩window.onpopstate
并检查下一个网址。无论哪种方式,整个中间件功能看起来都像
const middleware = store =>
return next => action =>
if (actionWillCauseSpellToBeNeeded(action))
makeAPICall()
.then(transformAPIToAction)
.catch(transformError)
.then(store.dispatch)
return next(action)
【讨论】:
以上是关于在路由加载时将模型加载到 redux 存储的最佳方法的主要内容,如果未能解决你的问题,请参考以下文章
如何在更新 Laravel 中的记录时将表单发布数据加载到模型中