2017-09-18 206 views
0

我正在實現一個對話框,詢問用戶他是否想從DataTable中刪除一個Item,如果他同意,史詩應該向後端發送DELETE請求,然後更新DataTable的狀態以顯示沒有刪除的項目。我的問題是史詩,當我分派打開模式對話框的OPEN_DELETE_DIALOG動作時,redux-observable開始執行DELETE_DATA動作,並向後端發送一串DELETE請求,即使沒有單擊應分派DELETE_DATA動作的AGREE選項。 當用戶調度DELETE_DATA動作時,史詩應該只發送DELETE請求,我該如何實現?如何使用redux-observable進行DELETE操作?

這是我的話單元(在這種情況下,刪除角色):

class DeleteDialog extends React.Component { 
    render() { 
     return (
     <div> 
      <MenuItem onClick={_ => { 
       console.log(`Edit ${JSON.stringify(this.props.item)}`) 
       this.props.openDeleteDialog(this.props.item) 
      }}> 
      <IconButton aria-label="Edit"> 
       <DeleteIcon /> 
      </IconButton> 
      <Typography> 
       Delete 
      </Typography> 
      </MenuItem> 
      <Dialog open={this.props.open} onRequestClose={this.props.cancelDeleteData}> 
      <DialogTitle>{"Delete Alert"}</DialogTitle> 
      <DialogContent> 
       <DialogContentText> 
       Are you sure you want to delete: {this.props.item.name} 
       </DialogContentText> 
      </DialogContent> 
      <DialogActions> 
       <Button onClick={this.props.cancelDeleteData} color="primary"> 
       Cancel 
       </Button> 
       <Button onClick={this.props.deleteData(this.props.item)} color="primary"> 
       Agree 
       </Button> 
      </DialogActions> 
      </Dialog> 
     </div> 
     ); 
    } 
} 

const mapStateToProps = state => ({ 
    open: state.role.delete.open, 
}) 

const mapDispatchToProps = dispatch => ({ 
    ...deleteDispatchesForScope(scopes.ROLE, dispatch) 
}) 

這是我行動的創造者,它是通用的,因此範圍可以是用戶,角色等:

export const actionTypes = { 
    OPEN_DELETE_DIALOG: 'OPEN_DELETE_DIALOG', 
    DELETE_DATA: 'DELETE_DATA', 
    CANCEL_DELETE_DATA: 'CANCEL_DELETE_DATA' 
} 

export const deleteActionTypesForScope = scope => ({ 
    OPEN_DELETE_DIALOG: `${scope}_${actionTypes.OPEN_DELETE_DIALOG}`, 
    DELETE_DATA: `${scope}_${actionTypes.DELETE_DATA}`, 
    CANCEL_DELETE_DATA: `${scope}_${actionTypes.CANCEL_DELETE_DATA}` 
}) 

export const deleteActionForScope = scope => { 
    const actionTypes = deleteActionTypesForScope(scope); 
    return { 
     openDeleteDialog: item => ({ 
      type: actionTypes.OPEN_DELETE_DIALOG, 
      item: item, 
      open: true 
     }), 
     deleteData: item => ({ 
      type: actionTypes.DELETE_DATA, 
      item: item, 
      open: false 
     }), 
     cancelDeleteData: _ => ({ 
      type: actionTypes.CANCEL_DELETE_DATA, 
      item: {}, 
      open: false 
     }) 
    } 
} 

export const deleteDispatchesForScope = (scope, dispatch) => { 
    const actionCreators = deleteActionForScope(scope); 
    return { 
     openDeleteDialog: item => dispatch(actionCreators.openDeleteDialog(item)), 
     deleteData: item => dispatch(actionCreators.deleteData(item)), 
     cancelDeleteData: _ => dispatch(actionCreators.cancelDeleteData()) 
    } 
} 

我的EPIC是這樣的:

const deleteRolEpic = (action$, store) => (
    action$.ofType(actionTypes.DELETE_DATA) 
     .filter(_ => !store.getState().rol.delete.loading) 
     .switchMap(action => { 
      let rolpath = 'roles/' + action.item.id; 
      return Observable.fromPromise(axios.delete(rolpath)) 
       .map(response => { 
        history.push('/roles'); 
       }) 
     }) 
) 

哪裏歷史重定向到路哪裏是我的DataTable在這種情況下,角色。另外,我正在使用Axios將我的請求發送到後端。 我得到的錯誤是這樣的:

proxyConsole.js:56 Warning: setState(...): Cannot update during an existing state transition (such as within `render` or another component's constructor). Render methods should be a pure function of props and state; constructor side-effects are an anti-pattern, but can be moved to `componentWillMount`. 
__stack_frame_overlay_proxy_console__ @ proxyConsole.js:56 
printWarning @ warning.js:35 
warning @ warning.js:59 
getInternalInstanceReadyForUpdate @ ReactUpdateQueue.js:54 
enqueueSetState @ ReactUpdateQueue.js:209 
./node_modules/react/lib/ReactBaseClasses.js.ReactComponent.setState @ ReactBaseClasses.js:64 
onStateChange @ connectAdvanced.js:205 
notify @ Subscription.js:26 
notifyNestedSubs @ Subscription.js:65 
onStateChange @ connectAdvanced.js:202 
dispatch @ createStore.js:173 
dispatch @ VM4042:2 
(anonymous) @ createEpicMiddleware.js:59 
dispatch @ VM4042:2 
deleteData @ delete-actions.js:38 
render @ RolDeleteDialog.js:54 
(anonymous) @ ReactCompositeComponent.js:795 
measureLifeCyclePerf @ ReactCompositeComponent.js:75 
_renderValidatedComponentWithoutOwnerOrContext @ ReactCompositeComponent.js:794 
_renderValidatedComponent @ ReactCompositeComponent.js:821 
_updateRenderedComponent @ ReactCompositeComponent.js:745 
_performComponentUpdate @ ReactCompositeComponent.js:723 
updateComponent @ ReactCompositeComponent.js:644 
receiveComponent @ ReactCompositeComponent.js:546 
receiveComponent @ ReactReconciler.js:124 
_updateRenderedComponent @ ReactCompositeComponent.js:753 
_performComponentUpdate @ ReactCompositeComponent.js:723 
updateComponent @ ReactCompositeComponent.js:644 
performUpdateIfNecessary @ ReactCompositeComponent.js:560 
performUpdateIfNecessary @ ReactReconciler.js:156 
runBatchedUpdates @ ReactUpdates.js:150 
perform @ Transaction.js:143 
perform @ Transaction.js:143 
perform @ ReactUpdates.js:89 
flushBatchedUpdates @ ReactUpdates.js:172 
closeAll @ Transaction.js:209 
perform @ Transaction.js:156 
batchedUpdates @ ReactDefaultBatchingStrategy.js:62 
batchedUpdates @ ReactUpdates.js:97 
dispatchEvent @ ReactEventListener.js:147 
proxyConsole.js:56 Warning: Failed prop type: Invalid prop `onClick` of type `object` supplied to `ButtonBase`, expected `function`. 
    in ButtonBase (created by withStyles(ButtonBase)) 
    in withStyles(ButtonBase) (created by Button) 
    in Button (created by withStyles(Button)) 
    in withStyles(Button) (at RolDeleteDialog.js:54) 
    in div (created by DialogActions) 
    in div (created by DialogActions) 
    in DialogActions (created by withStyles(DialogActions)) 
    in withStyles(DialogActions) (at RolDeleteDialog.js:50) 
    in div (created by Paper) 
    in Paper (created by withStyles(Paper)) 
    in withStyles(Paper) (created by Dialog) 
    in Transition (created by Fade) 
    in Fade (created by withTheme(Fade)) 
    in withTheme(Fade) (created by Dialog) 
    in div (created by Modal) 
__stack_frame_overlay_proxy_console__ @ proxyConsole.js:56 
printWarning @ warning.js:35 
warning @ warning.js:59 
checkReactTypeSpec @ checkReactTypeSpec.js:80 
validatePropTypes @ ReactElementValidator.js:162 
createElement @ ReactElementValidator.js:216 
createEagerElementUtil @ createEagerElementUtil.js:31 
(anonymous) @ createEagerFactory.js:18 
render @ withStyles.js:345 
(anonymous) @ ReactCompositeComponent.js:795 
measureLifeCyclePerf @ ReactCompositeComponent.js:75 
_renderValidatedComponentWithoutOwnerOrContext @ ReactCompositeComponent.js:794 
_renderValidatedComponent @ ReactCompositeComponent.js:821 
performInitialMount @ ReactCompositeComponent.js:361 
mountComponent @ ReactCompositeComponent.js:257 
mountComponent @ ReactReconciler.js:45 
performInitialMount @ ReactCompositeComponent.js:370 
mountComponent @ ReactCompositeComponent.js:257 
mountComponent @ ReactReconciler.js:45 
performInitialMount @ ReactCompositeComponent.js:370 
mountComponent @ ReactCompositeComponent.js:257 
mountComponent @ ReactReconciler.js:45 
mountChildren @ ReactMultiChild.js:236 
_createInitialChildren @ ReactDOMComponent.js:703 
mountComponent @ ReactDOMComponent.js:522 
mountComponent @ ReactReconciler.js:45 
mountChildren @ ReactMultiChild.js:236 
_createInitialChildren @ ReactDOMComponent.js:703 
mountComponent @ ReactDOMComponent.js:522 
mountComponent @ ReactReconciler.js:45 
performInitialMount @ ReactCompositeComponent.js:370 
mountComponent @ ReactCompositeComponent.js:257 
mountComponent @ ReactReconciler.js:45 
performInitialMount @ ReactCompositeComponent.js:370 
mountComponent @ ReactCompositeComponent.js:257 
mountComponent @ ReactReconciler.js:45 
mountChildren @ ReactMultiChild.js:236 
_createInitialChildren @ ReactDOMComponent.js:703 
mountComponent @ ReactDOMComponent.js:522 
mountComponent @ ReactReconciler.js:45 
performInitialMount @ ReactCompositeComponent.js:370 
mountComponent @ ReactCompositeComponent.js:257 
mountComponent @ ReactReconciler.js:45 
performInitialMount @ ReactCompositeComponent.js:370 
mountComponent @ ReactCompositeComponent.js:257 
mountComponent @ ReactReconciler.js:45 
performInitialMount @ ReactCompositeComponent.js:370 
mountComponent @ ReactCompositeComponent.js:257 
mountComponent @ ReactReconciler.js:45 
performInitialMount @ ReactCompositeComponent.js:370 
mountComponent @ ReactCompositeComponent.js:257 
mountComponent @ ReactReconciler.js:45 
performInitialMount @ ReactCompositeComponent.js:370 
mountComponent @ ReactCompositeComponent.js:257 
mountComponent @ ReactReconciler.js:45 
mountChildren @ ReactMultiChild.js:236 
_createInitialChildren @ ReactDOMComponent.js:703 
mountComponent @ ReactDOMComponent.js:522 
mountComponent @ ReactReconciler.js:45 
performInitialMount @ ReactCompositeComponent.js:370 
mountComponent @ ReactCompositeComponent.js:257 
mountComponent @ ReactReconciler.js:45 
mountComponentIntoNode @ ReactMount.js:104 
perform @ Transaction.js:143 
batchedMountComponentIntoNode @ ReactMount.js:126 
batchedUpdates @ ReactDefaultBatchingStrategy.js:60 
batchedUpdates @ ReactUpdates.js:97 
_renderNewRootComponent @ ReactMount.js:319 
_renderSubtreeIntoContainer @ ReactMount.js:401 
renderSubtreeIntoContainer @ ReactMount.js:342 
renderLayer @ Portal.js:130 
componentDidMount @ Portal.js:70 
(anonymous) @ ReactCompositeComponent.js:264 
measureLifeCyclePerf @ ReactCompositeComponent.js:75 
(anonymous) @ ReactCompositeComponent.js:263 
notifyAll @ CallbackQueue.js:76 
close @ ReactReconcileTransaction.js:80 
closeAll @ Transaction.js:209 
perform @ Transaction.js:156 
perform @ Transaction.js:143 
perform @ ReactUpdates.js:89 
flushBatchedUpdates @ ReactUpdates.js:172 
closeAll @ Transaction.js:209 
perform @ Transaction.js:156 
batchedUpdates @ ReactDefaultBatchingStrategy.js:62 
batchedUpdates @ ReactUpdates.js:97 
dispatchEvent @ ReactEventListener.js:147 
invariant.js:44 Uncaught Error: Expected onClick listener to be a function, instead got type object 
    at invariant (invariant.js:44) 
    at Object.putListener (EventPluginHub.js:132) 
    at Object.putListener (ReactDOMComponent.js:177) 
    at CallbackQueue.notifyAll (CallbackQueue.js:76) 
    at ReactReconcileTransaction.close (ReactReconcileTransaction.js:80) 
    at ReactReconcileTransaction.closeAll (Transaction.js:209) 
    at ReactReconcileTransaction.perform (Transaction.js:156) 
    at batchedMountComponentIntoNode (ReactMount.js:126) 
    at Object.batchedUpdates (ReactDefaultBatchingStrategy.js:60) 
    at Object.batchedUpdates (ReactUpdates.js:97) 
    at Object._renderNewRootComponent (ReactMount.js:319) 
    at Object._renderSubtreeIntoContainer (ReactMount.js:401) 
    at Object.renderSubtreeIntoContainer [as unstable_renderSubtreeIntoContainer] (ReactMount.js:342) 
    at Portal.renderLayer (Portal.js:130) 
    at Portal.componentDidMount (Portal.js:70) 
    at ReactCompositeComponent.js:264 
    at measureLifeCyclePerf (ReactCompositeComponent.js:75) 
    at ReactCompositeComponent.js:263 
    at CallbackQueue.notifyAll (CallbackQueue.js:76) 
    at ReactReconcileTransaction.close (ReactReconcileTransaction.js:80) 
    at ReactReconcileTransaction.closeAll (Transaction.js:209) 
    at ReactReconcileTransaction.perform (Transaction.js:156) 
    at ReactUpdatesFlushTransaction.perform (Transaction.js:143) 
    at ReactUpdatesFlushTransaction.perform (ReactUpdates.js:89) 
    at Object.flushBatchedUpdates (ReactUpdates.js:172) 
    at ReactDefaultBatchingStrategyTransaction.closeAll (Transaction.js:209) 
    at ReactDefaultBatchingStrategyTransaction.perform (Transaction.js:156) 
    at Object.batchedUpdates (ReactDefaultBatchingStrategy.js:62) 
    at Object.batchedUpdates (ReactUpdates.js:97) 
    at dispatchEvent (ReactEventListener.js:147) 

回答

0

更改此:

<Button onClick={this.props.deleteData(this.props.item)} color="primary"> 
    Agree 
</Button> 

要:

<Button onClick={ e => this.props.deleteData(this.props.item)} color="primary"> 
    Agree 
</Button> 

否則你將派遣 「deleteData」 每個組件呈現時間。