我是React和Redux的新手,我正在尝试编写一个简单的应用程序,其中一个人可以提交图像的URL,它将显示在页面上。请注意,到目前为止还没有应用程序的后端。
export const addImage = (url) => {
return {
type: ADD_IMAGE,
key: Guid.create().toString(),
payload: url
}
}
添加图像会创建ADD_IMAGE类型的操作,因此我的reducer会更新状态。但是我也检查URL是否已经在列表中。
switch (action.type) {
case ADD_IMAGE:
if (state.find(image => image.url === action.payload)) {
return state;
} else {
return(
[
...state,
{key: action.key, url: action.payload}
]
);
}
break;
default:
}
问题是当我拒绝帖子因为URL已经处于状态时我也想通过在表单旁边的div中显示该消息来向用户传达该消息。从我所读过的内容来看,我认为我不应该尝试从减速器(如果可能的话)访问React状态并且......好吧......我只是卡住了。我一直试图找到一个关于如何做到这一点的简单指南,但我找不到任何我能理解的内容。添加数据库后,我想我将不得不这样做作为异步过程的一部分,但我现在有了它,我想应该有一些简单的解决方案。
答案 0 :(得分:1)
您开始在减速器中引入逻辑,这将不可避免地导致需要处理减速器范围之外的某些状态的情况。
解决方案是使用中间件包redux-thunk(或类似的包)将您的reducer逻辑转移到thunk
。这允许您将特殊类型的操作视为函数,这意味着您可以使用特定的操作相关逻辑扩展普通操作。您在特定条件下需要调度错误操作的示例是redux-thunk的一个很好的用例。
下面是一个如何将逻辑从reducer中拉出来的示例。您应该注意,与reducers不同,thunk明确支持获取状态并通过getState
和dispatch
函数调度后续操作。
Thunk示例
export const addImage = (url) => {
return (dispatch, getState) => {
const key = Guid.create().toString()
dispatch({
type: ADD_IMAGE,
key,
payload: url
})
const state = getState()
// you would want to use a `selector` here to locate the existing image
// within the state tree
const exists = selectors.images.exists(state, url)
if (exists) {
dispatch(actions.ERROR_IMAGE_EXISTS({key, url}))
}
}
}
关于选择器的说明
您将看到我使用selector
来确定图片是否存在。与thunks
放置调度逻辑的地方相同,selector
是放置状态遍历逻辑的地方。它们用于返回状态树的部分或提供简单的状态实用程序,例如上面显示的exists
函数。软件包可以提供帮助,例如reselect。
关注评论中的问题
Redux中的选择器不是内置的东西吗?
不,他们不是。选择器是一种构建在redux之上的概念,这个概念作为一个放置状态搜索,缓存,读取逻辑的地方存在。这会从你的thunks和组件中提取有时复杂的状态遍历逻辑,并进入一个漂亮整洁,结构化的选择器集合。
为什么要使用选择器而不是state.images.find(i => i.url === url)
?
如果您使用选择器包,那么您获得的好处远远大于良好的关注点分离,您可以获得很大的性能提升(请参阅下面的使用示例)。
以下是热门reselect套餐的头条新闻:
为什么actions.ERROR_IMAGE_EXISTS(url)
不适合我
因为我只是为了这个例子。关键是你可以从thunk中发送动作,你如何声明或获取对动作的访问权限取决于你。我倾向于将所有共享操作集中到我actions
的{{1}}对象中。
选择器使用示例
以下是我现实代码中的一个示例,它显示了我如何使用选择器将状态的一部分作为props传递给反应组件:
import
这些选择器中的每一个都在找到状态树的正确部分并将其交还准备使用。很好,整洁,如果你使用reselector,效率非常高。