如何将 thunk 或回调函数传递给 redux 操作。在 redux store 中为模态和 toast 确认通知序列化函数

Posted

技术标签:

【中文标题】如何将 thunk 或回调函数传递给 redux 操作。在 redux store 中为模态和 toast 确认通知序列化函数【英文标题】:How to pass a thunk or callback function into a redux action. Serializing functions in a redux store for modals and toast confirm notifications 【发布时间】:2017-01-29 08:59:15 【问题描述】:

当使用带有确认按钮的通用模式或 toast 时,能够将操作传递到此组件中非常有用,以便在您单击确认时可以分派它。

动作可能如下所示:

export function showConfirm(modalConfirm) 
  return 
    type: 'MODALS/SHOW_MODAL',
    payload: 
      modalId: getUuid(),
      modalType: 'CONFIRM',
      modalConfirm : modalConfirm,
    ,
  ;

其中modalConfirm 是另一个动作对象,例如:

const modalConfirm = 
  type: 'MAKE_SOME_CHANGES_AFTER_CONFIRM',
  payload: 

modalConfirm 操作使用dispatch(modalConfirm) 甚至dispatch(Object.assign(, modalConfirm, someResultFromTheModal) 在模态组件内部调度

不幸的是,这个解决方案只有在 modalConfirm 是一个简单的 redux 操作对象时才有效。这个系统显然是非常有限的。无论如何你可以传递一个函数(比如一个 thunk)而不是一个简单的对象?

理想情况下,功能齐全的东西是这样的:

    const modalConfirm = (someResultFromTheModal) => 
      return (dispatch, getState)
        dispatch(
          type: 'MAKE_SOME_UPDATES',
          payload: someResultFromTheModal
        )
        dispatch(
          type: 'SAVE_SOME_STUFF',
          payload: http(
            method: 'POST',
            url: 'api/v1/save',
            data: getState().stuffToSave
          )
        )
      
    

【问题讨论】:

【参考方案1】:

有趣的是,将动作对象放在商店中并将其作为道具传递给通用对话框正是我自己想出的方法。实际上,我有一篇博客文章正在等待发布,描述这个想法。

您的问题的答案是“是的,但是....”。根据 http://redux.js.org/docs/FAQ.html#organizing-state-non-serializable 的 Redux 常见问题解答,完全可以将不可序列化的值(例如函数)放入您的操作和存储中。但是,这通常会导致时间旅行调试无法按预期工作。如果这不是您关心的问题,那么请继续。

另一种选择是将您的模态确认分成两部分。让初始模态确认仍然是一个普通的动作对象,但使用中间件来监视被调度的对象,并从那里做额外的工作。这是 Redux-Saga 的一个很好的用例。

【讨论】:

【参考方案2】:

我最终将字符串别名用于集中注册动作的动作库。

模态发射器动作包含一个带有functionAliasfunctionInputs 的对象

export function confirmDeleteProject(projectId) 
  return ModalActions.showConfirm(
    message: 'Deleting a project it permanent. You will not be able to undo this.',
    modalConfirm: 
      functionAlias: 'ProjectActions.deleteProject',
      functionInputs:  projectId 
    
  )

其中 'ProjectActions.deleteProject' 是任何类型的复杂操作的别名,例如:

export function deleteProject(projectId) 
  return (dispatch)=>
    dispatch(
      type: 'PROJECTS/DELETE_PROJECT',
      payload: http(
        method: 'DELETE',
        url: `http://localhost:3000/api/v1/projects/$projectId`,
      ).then((response)=>
        dispatch(push(`/`))
      ),
      meta: 
        projectId
      
    );
  

函数在库模块中注册如下:

import * as ProjectActions from '../../actions/projects.js';

const library = 
  ProjectActions: ProjectActions,


export const addModule = (moduleName, functions) => 
  library[moduleName] = functions


export const getFunction = (path) => 
  const [moduleName, functionName] = path.split('.');

  // We are getting the module only
  if(!functionName)
    if(library[moduleName])
      return library[moduleName]
    
    else
      console.error(`Module: $moduleName could not be found.`);
    
  
  // We are getting a function
  else
    if(library[moduleName] && library[moduleName][functionName])
      return library[moduleName][functionName]
    
    else
      console.error(`Function: $moduleName.$functionName could not be found.`);
    
  

modalConfirm 对象是通过 props 传入 modal 的。 modal 组件需要上面模块中的getFunction 函数。 modalConfirm 对象转化为函数如下:

const modalConfirmFunction = (extendObject, modalConfirm) => 
  const functionFromAlias = getFunction(modalConfirm.functionAlias);
  if(functionFromAlias)
    dispatch(functionFromAlias(Object.assign(, modalConfirm.functionInputs, extendObject)));
  

如您所见,此函数可以接收来自模态的输入。它可以执行任何类型的复杂动作或重击。这个系统不会打破时间旅行,但集中式图书馆有点缺点。

【讨论】:

自从得到答案后您是否仍在使用这种方法,或者您是否继续使用不同的方法? 是的,这是我能想到的唯一一个可以承受时间旅行/应用程序重新启动或在多线程电子应用程序中工作的系统。尽管如此,在诸如网站之类的单线程环境中工作时,我只使用承诺缓存。这是一个更好的系统,但不是那么健壮......您可能会在这里有所了解:github.com/MrBlenny/react-redux-promise-modals/tree/master/src 该示例特定于模态但可以通用。承诺的 id 在动作内部传递,然后该承诺被解决/拒绝

以上是关于如何将 thunk 或回调函数传递给 redux 操作。在 redux store 中为模态和 toast 确认通知序列化函数的主要内容,如果未能解决你的问题,请参考以下文章

使用 promise/thunk 通过 action 将参数传递给 reducer

如何使用 react-redux-firebase 将 'auth' 或 'profile' 对象传递给 firestoreConnect()?

Prettyphoto - 如何将唯一参数传递给回调函数

如何将回调作为参数传递给另一个函数

更新后如何将函数传递给 SetState 回调? (反应)

角度拖放-如何将参数传递给onStart回调函数