在 React/Redux 应用程序中正确隔离组件,但允许在彼此之间传递回调
Posted
技术标签:
【中文标题】在 React/Redux 应用程序中正确隔离组件,但允许在彼此之间传递回调【英文标题】:Properly isolating components in React/Redux app, but permit passing callbacks between each others 【发布时间】:2018-01-06 16:24:06 【问题描述】:我刚开始用 Redux 学习 React,所以请多多包涵。 我遵循 Redux 有点入门,到目前为止,一切都很好。但是按照“基本”和“高级”redux 文档部分,我将在我的所有组件都被隔离的位置结束。这很好。除了我的一个组件旨在显示通知、关闭和删除它们。 另一种是模式,需要 4 个参数才能工作:一个带有标题文本部分,与正文部分相同,一个布尔值用于设置是否显示,一个用于在单击确认按钮时触发确认操作。 当用户想要删除通知时,我的通知组件需要显示模式。两个组件都有一个由 redux 处理的状态。
这里有一些片段。
下面是通知缩减程序,它处理解除删除和获取通知。很简单。
// The notifications reducer
let initialState =
isFetching: false,
didInvalidate: false,
notifications: []
const notifications = (state = initialState, action) =>
switch (action.type)
case 'DISMISS':
return ...state, notifications: state.notifications.map(element => element.id === action.id ? ...element, dismissed: !element.dismissed : element)
case 'DISMISS_ALL':
return ...state, notifications: state.notifications.map(element => return ...element, dismissed: false )
case 'DELETE':
return ...state, notifications: state.notifications.filter(element => element.id !== action.id)
case 'DELETE_ALL':
return ...state, notifications: []
case 'INVALIDATE':
return ...state, didInvalidate: true
case 'REQUEST':
return ...state, isFetching: true, didInvalidate: false
case 'RECEIVE':
return ...state, isFetching: false, didInvalidate: false, notifications: action.posts, lastUpdate: action.receivedAt
default:
return state
export default notifications
然后是通知操作。我这里的重点是deleteNotification
和deleteAllNotifications
actions,它们必须绑定模态打开并等待其响应,然后触发删除,并且仅在此之后。
那些需要(我猜)像fetchNotifications
操作一样工作,调用另一个操作(模态的),而不是像fetchNotifications
那样进行数据获取。
// The notifications actions
//@flow
import axios from 'axios'
/**
* NOTIFICATIONS ACTION CREATORS
*/
export const dismissNotification = (id: number) =>
return type: 'DISMISS', id
export const dismissAllNotifications = () =>
return type: 'DISMISS_ALL'
export const deleteNotification = (id: number) =>
return type: 'DELETE', id
export const deleteAllNotifications = () =>
return type: 'DELETE_ALL'
/**
* DATABASE NOTIFICATIONS ACTION CREATORS
*/
export const invalidate = (uri: string) =>
return type: 'INVALIDATE', uri
export const requestNotifications = (uri: string) =>
return type: 'REQUEST', uri
export const receiveNotifications = (uri: string, json: string) =>
return
type: 'RECEIVE',
uri,
posts: json,
receivedAt: Date.now()
export const fetchNotifications = (uri: string) =>
return (dispatch: any) =>
dispatch(requestNotifications(uri))
return axios.get(uri)
.then(
response => response.data,
error => console.log('Error', error) // TODO logger les erreurs
)
.then(json =>
dispatch(receiveNotifications(uri, json))
)
最后,模态的减速器。 reducer 的重点是通过headerMessage
和bodyMessage
处理显示(可见或不可见)中的文本。
id
在这里告诉模态是否必须在一个或一大堆元素上调度删除。这对我来说很脏。例如,它应该只返回一个确认,通知操作将捕获该确认作为响应。
let initialState =
showModal: false,
headerMessage: '',
bodyMessage: '',
id: false
const modal = (state = initialState, action) =>
switch (action.type)
case 'MODAL_DISPLAY':
return ...state,
showModal: action.showModal,
headerMessage: action.headerMessage,
bodyMessage: action.bodyMessage,
id: action.id
case 'MODAL_HIDE':
return ...state,
showModal: action.showModal,
headerMessage: action.headerMessage,
bodyMessage: action.bodyMessage,
id: action.id
default:
return state
export default modal
需要明确的是,模态组件和通知组件位于不同的目录中。我希望模态组件可以在任何上下文中使用。这里是关于通知的,但如果我希望它与通知之外的任何其他组件一起使用,比如说用户的个人资料,我不应该专门绑定到任何组件。
就我而言,通知组件是调用模式的组件。这就是“驱动”全球行为的原因。但我想我没有把这一切做好。这是我的通知组件索引:
//@flow
import React from 'react'
import render from 'react-dom'
import thunkMiddleware from 'redux-thunk'
import createLogger from 'redux-logger'
import Provider from 'react-redux'
import createStore, applyMiddleware, compose from 'redux'
import fetchNotifications from './store/actions/NotificationsActions'
import NotifiationsApp from './store/reducers/reducerCombiner'
import App from './components/App'
import ModalContainer from '../modal-component/store/containers/ModalContainer'
const loggerMiddleware: any = createLogger()
const composeEnhancers: any = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose
const store: any = createStore(
NotifiationsApp,
composeEnhancers(
applyMiddleware(
thunkMiddleware,
loggerMiddleware
)
)
)
store.dispatch(fetchNotifications('/app_dev.php/notifications/load?offset=0&limit=10'))
render(
<Provider store=store>
<div>
<App/>
<ModalContainer />
</div>
</Provider>,
document.getElementById('notifications-component')
)
如您所见,我将ModalContainer
称为“智能”模态组件抽象。
最后,这是我的错; ModalContainer
与通知组件相关联,我想在onConfirm
被触发时“返回”确认事件:
import connect from 'react-redux'
import deleteAllNotifications, deleteNotification from '../../../notifications-component/store/actions/NotificationsActions'
import hideModal from '../actions/ModalActions'
import ModalInstance from '../../components/Modal'
const getModalProperties = modal =>
return modal
const mapStateToProps = state =>
return getModalProperties(state.modal)
const mapDispatchToProps = dispatch =>
return
onCancel: () =>
dispatch(hideModal(false, false, '', ''))
,
onConfirm: id => // BELOW, THIS IS VERY BAD!!
id ? dispatch(deleteNotification(id)) : dispatch(deleteAllNotifications())
dispatch(hideModal(false, '', '', false))
const ModalDisplay = connect(
mapStateToProps,
mapDispatchToProps
)(ModalInstance)
export default ModalDisplay
我在这方面苦苦挣扎。请帮忙!
【问题讨论】:
【参考方案1】:我不确定我是否理解正确,但您似乎正在寻找ownProps
。您想将一个函数传递给您的 ModalWindow
组件,该函数应在调用确认函数后调用,对吗?这样你就有了像
<ModalContainer onConfirm=myHandler/>
在这种情况下,您的mapDispatchToProps
需要考虑您传递给容器的道具,例如
const mapDispatchToProps = (dispatch, ownProps) =>
return
onCancel: () =>
dispatch(hideModal(false, false, '', ''))
,
onConfirm: id => // BELOW, THIS IS VERY BAD!!
id ? dispatch(deleteNotification(id)) : dispatch(deleteAllNotifications())
dispatch(hideModal(false, '', '', false));
ownProps.onConfirm && ownProps.onConfirm(id);
【讨论】:
【参考方案2】:总的来说,您走在正确的轨道上。方便的是,我刚刚发布了Practical Redux, Part 10: Managing Modals and Context Menus,它演示了如何使用 Redux 构建和控制模式、上下文菜单和通知。这包括如何在模式关闭时处理“返回值”。
具体回答您的问题:处理 ID 以清除一个通知与所有通知对我来说根本不“脏”或“坏” - 这种方法应该没问题。
【讨论】:
以上是关于在 React/Redux 应用程序中正确隔离组件,但允许在彼此之间传递回调的主要内容,如果未能解决你的问题,请参考以下文章
使用通过 react、redux 和 react-redux 完成的组件以及在 react 应用程序中使用 webpack 构建时出错
将firestore onSnapShot与react redux一起使用的正确方法