Redux thunk 在下一个操作之前没有解析 + then 不是函数或调度未定义

Posted

技术标签:

【中文标题】Redux thunk 在下一个操作之前没有解析 + then 不是函数或调度未定义【英文标题】:Redux thunk not resolving before next action + then is not a function or dispatch undefined 【发布时间】:2017-01-06 05:58:22 【问题描述】:

一直在开发一个 react/redux 应用程序,但我一直在努力解决这个问题。

问题 - 我正在使用 wzywyg 编辑器更新文件。当我上传照片时,应用程序会在操作完成图像处理之前尝试插入图像。因此,导致图像 url 未定义。当我上传第二张图片时,会插入第一张图片,依此类推。

很明显,在调用下一个操作之前,thunk 没有解决。

更多详情

我的应用程序中有一个文本编辑器(summernote-react)。当用户上传图片时,onImageUpload 会触发并触发 handleImageUpload。 从那里,我通过 mapStatetoProps 调度一个动作,并处理图像以供上传。 图片处理完后,应该返回编辑器,将图片路径嵌入到编辑器中进行预览。

现在,我遇到了相同的错误模式,即调度未定义,然后不是函数。我错过了什么?

addUploadToDocument(...).then is not a function
Uncaught TypeError: Cannot read property 'then' of undefined

我可以确认以下几点: - Redux-thunk 设置正确。它在我们的生产版本中工作和发射。 - 正在从我的组件调用该操作。只是不确定是否派送。我可以成功上传图片,但是在解决操作之前会发起回调。

这是我的操作代码:

// actions.js
// thunk
export function loadImage(document, file) 
  return (dispatch, getState) => 
   return  dispatch(addUploadToDocument(document, file))
      .then(() => 
        console.log('Thunk is loaded.. chyeah.');
        var uploads = this.props.uploads
        var image = uploads[uploads.length - 1]    
        ReactSummernote.insertImage(image.previewURL, $image => 
          $image.css("width", Math.floor($image.width() / 2));
          $image.attr("alt", image.name);
        );
      );
  

//image processing action
export function addUploadToDocument(document, file)     
  return (dispatch, getState) => 
    //const position = getState().bodyEditorSelection.index
    const base64Reader = new FileReader()    
    base64Reader.addEventListener('load', function() 
      const base64 = base64Reader.result.replace(/data:.*?base64,/, '')
      const key = Math.random().toString(36).substring(7)    
      const destination_path = `/uploads/$document.name/$key-$file.name`
      return dispatch(
        type: DOCUMENT_ADD_UPLOAD,
        payload: 
          path: destination_path,
          type: file.type,
          base64: base64,
          name: document.name,
          previewURL: window.URL.createObjectURL(file),
          //position: position
        
      )
    )
    base64Reader.readAsDataURL(file)
  

这是我的组件。

  handleImageUpload (files, editor, welEditable) 
    var file = files[files.length -1];
    this.props.loadImage(this.props.document, file)
  
  render() 
    this.syncBodyEditorState()
    this.state = this.state || 
    return (
        <ReactSummernote
        value=this.props.body
        options=
          height: 750,
          dialogsInBody: true,
          toolbar: [
            ["style", ["style"]],
            ["font", ["bold", "underline", "clear"]],
            ["fontname", ["fontname"]],
            ["para", ["ul", "ol", "paragraph"]],
            ["table", ["table"]],
            ["insert", ["link", "picture", "video"]],
            ["view", ["codeview"]]
          ]
        
        onImageUpload=this.handleImageUpload
        onChange=this.handleChange
      />
    )
  


function mapStateToProperties(state) 
  const currentDocument = currentDocumentSelector(state).currentDocument    
  return 
    document: currentDocument,
    bodyEditorSelection: state.bodyEditorSelection,
    body: currentDocument.content.body,
    uploads: currentDocument.content.uploads
  
    
export default connect(mapStateToProperties, 
  SummernoteEditor,
  updateDocumentBody,
  updateBodyEditorSelection,
  addUploadToDocument,
  loadImage
)(SummernoteEditor)

我错过了一些琐碎的事情吗?我看了几十个例子,thunk让我难过!

提前感谢您的帮助。

【问题讨论】:

【参考方案1】:

现在你的addUploadToDocument 函数没有返回一个promise,尽管你.then 你的dispatch 方法(它只是一个返回一个普通对象的thunk)。如果您需要继续,您可以将addUploadToDocument 函数的内容包装在一个promise 中,然后它就可以使用了。这里有一些不同的方法,通过一些折射让你开始(假设“加载”事件只能发生一次):

export function loadImage(document, file) 
  return (dispatch, getState) => 
    const base64Reader = new FileReader();

    const promise = new Promise((resolve, reject)=> 
      base64Reader.addEventListener('load', resolve)
    )
        .then(()=> 
          const base64 = base64Reader.result.replace(/data:.*?base64,/, '')
          const key = Math.random().toString(36).substring(7)
          const destination_path = `/uploads/$document.name/$key-$file.name`
          dispatch(
            type: DOCUMENT_ADD_UPLOAD,
            payload: 
              path: destination_path,
              type: file.type,
              base64: base64,
              name: document.name,
              previewURL: window.URL.createObjectURL(file),
              //position: position
            
          )
        )
        .then(()=> 
          console.log('Thunk is loaded.. chyeah.');
          var uploads = this.props.uploads
          var image = uploads[uploads.length - 1]
          ReactSummernote.insertImage(image.previewURL, $image => 
            $image.css("width", Math.floor($image.width() / 2));
            $image.attr("alt", image.name);
          );
        )
    base64Reader.readAsDataURL(file);
    return promise;
   

【讨论】:

以上是关于Redux thunk 在下一个操作之前没有解析 + then 不是函数或调度未定义的主要内容,如果未能解决你的问题,请参考以下文章

使用 redux thunk 测试异步操作

使用 redux-thunk 取消之前的 fetch 请求

在 React Redux 中调度操作之前等待多个 Axios 调用

Redux thunk:如何等待异步操作的完成

使用 Redux-thunk 调用操作不起作用

redux-thunk:错误:动作必须是普通对象。使用自定义中间件进行异步操作