经过一些研究,我发现了一些关于stackoverflow的问题,这些问题与我要实现的目标有关,但是,我不觉得这些问题及其答案能为我提供我所寻找的“答案”或“方向”。
注意:即使我已经制作了2个项目并将redux实施到其中一个项目中,我还是很陌生。但是,我对C#或Go都不是陌生的,甚至对C也不是。根据我的经验,我只是习惯于某些体系结构,我想重现其中的一种。
这里是一个类似我的类似问题的漂亮的好模式:
情况:
所以说我有一些包含组件的页面。我希望这些页面/内容显示一些内容。我的功能之一是发现地图,为此,当客户移动时,他会从我的API中获取新零件。但是,我不想让服务器将新零件和已经发现的零件给我。
我的想法是使用服务MapService.js
。这只会存储发现的地图的发现部分,并自动向服务器询问新的部分,当然还要存储新的部分(concat)。
但是,我必须为此登录,所以我想要一个ApiService.js
来存储我的身份验证数据并自动将其放入我的每个请求中。
根据我所说的,我们将得到以下内容:
页面->组件->服务-> API
由此,API响应将由我的服务获取,处理并返回给组件。处理方式(将数据添加到前一个然后全部返回)
我在互联网上看到一个问题,它指的是“ MVCS”(模型视图控制器服务)模式,我想我正在寻找某种东西,但是我不确定如何在ReactJs中实现它。
Redux似乎是您在解决方案中无所不在的东西。我想用它作为“存储库”,可以通过服务而不是组件本身来管理它。但是,服务应该是在整个应用程序中共享的单个实例,我不知道诸如依赖注入之类的东西是否可以作为ReactJS中的解决方案
如果您需要更多详细信息,请随时提出任何修改:)
感谢您的帮助!
答案 0 :(得分:2)
这里是Redux中间件用法的一个最小示例。通常,redux开发人员正在使用库(为您提供中间件)来访问更合适的API。
Redux中间件是链接的,因此每个中间件都可以调用下一个中间件。每次调用dispatch
函数(您可以从react-redux connect获得它)时,都会调用该链的第一个中间件。在中间件中,如果没有下一个中间件,则将调用reducer。收到动作后,可以异步调用下一个中间件。 (Redux文档仍然比我的解释要好。
在我的示例中,有一个catService提供了调用rest API的功能。您的服务可以是任何东西(例如,Class实例或单例)。通常在React / Redux堆栈中,开发人员不使用面向对象的开发。
如果组件派发getCat(123)
,catMiddleware
将被(同步)调用。然后,将使用ID requestGetCat
调用123
。当requestGetCat
返回的承诺被解析后,将通过化简发送setCat
动作以更新redux状态。还原状态完成后,侦听cat items
对象的组件也会更新(触发重新渲染)。
这看起来很复杂,但实际上,它具有很好的可伸缩性和便利性。
// catService.js
// return a promise that return a cat object
const requestGetCat = id =>
fetch(`www.catcat.com/api/cat/${id}`)
.then(response => response.json())
// catTypes.js
export const GET_CAT = 'GET_CAT'
export const SET_CAT = 'SET_CAT'
// catActions.js
export const getCat = id => ({
type: GET_CAT,
id
})
export const setCat = (cat, id) => ({
type: SET_CAT,
id,
cat
})
// catReducer.js
const initialState = {
items: {}
}
const catReducer = (state = initialState, action) => {
if (action.type === SET_CAT) {
return {
items: {
...state.items,
[action.id]: action.cat
}
}
}
}
// catMiddleware.js
const handleGetCat = (next, action) => {
requestGetCat(action.id)
.then(cat => next(setCat(cat, action.id)))
// after retrieving the cat send an action to the reducers (or next middleware if it exist)
}
const actionHandlers = {
[GET_CAT]: handleGetCat
}
// receive every actions passing by redux (if not blocked)
// store: { dispatch, getState }
// next: next middleware or reducers (that set redux state)
// action: a redux action (dispatched) with at least type property
const catMiddleware = store => next => action => {
const handler = actionHandlers[action.type]
if (handler) {
handler(next, action)
} else {
// passing the action to the next middleware (or reducer - when there is no next middleware)
next(action)
}
}
// you have to apply your middleware
// and your reducer (see redux doc)
答案 1 :(得分:2)
这只是存储发现的地图的发现部分,并自动询问服务器有关新地图的部分,当然,也要存储新地图。
这是我过去想要做的,但是从未实现过解决方案。
问题是您本质上想“跨流”。
在Redux中,有两个单独的流,即调度一个操作以更新存储,并从存储中读取数据。这些中的每一个都与组件分开执行。通过调用将数据加载到商店中的操作将它们组合在一起,可以循环使用它们,从而触发组件的更新,然后从商店中读取内容。
基本上,您不能有从商店读取的非组件代码,如果数据丢失,则执行操作以加载数据,然后返回数据。
现在考虑一下,我想知道是否在不向视图组件中添加逻辑的情况下将其包装在提供逻辑的组件(HOC)中。
HOC将检查道具中指定位置的状态。如果找不到,它将分派一个动作来获取它并呈现加载显示。使用新位置更新状态后,它将更新并呈现包装的组件。
您可以选择始终渲染包装的组件并使它处理丢失的位置,直到用位置集更新它为止。
以下未经过研究的转储
加载程序HOC:
import React, { useEffect } from "react";
import actions from "./actions";
function withLocationLoader(Component) {
const Wrapper = function ({ location, locations, loadLocation, ...props }) {
useEffect(() => {
if (!locations[location]) {
loadLocation(location);
}
}, [locations]);
if (locations[location]) {
return <Component locations={locations} {...props} />;
}
return <div>Loading...</div>;
}
const mapStateToProps = (state, ownProps) => {
return { locations: state.locations };
};
const mapActionsToProps = {
loadLocation: actions.loadLocation,
};
return connect(
mapStateToProps,
mapActionsToProps
)(Wrapper);
}
export { withLoader };
组件:
function MyBareComponent({ locations }) {
return <div>{JSON.stringify(locations)}</div>;
}
const MyComponent = withLocationLoader(MyBareComponent);
export { MyComponent };
操作 :(使用Redux简化的中间件)
function setLocation(location, data) {
return { type: "SET_LOCATION", payload: { location, data } };
}
export function loadLocation(location) {
return dispatch =>
Promise.resolve({ geoData: "" }) // mock api request
.then(data => dispatch(setLocation(location, data)));
}