回调在ajax请求中不起作用?

Nan*_*ane 5 javascript ajax reactjs draftjs axios

我正在尝试使用草稿js构建contentEditor.这个功能正是从Facebook这样的网址中提取数据.但我坚持这部分.回调无效.

首先,我包裹着我的状态,compositeDecorator像这样

constructor(props) {
    super(props);
    const compositeDecorator = new CompositeDecorator([
        .... {
            strategy: linkStrategy,
            component: decorateComponentWithProps(linkComp, {
                passit
            })
        }
        ....
    ]);
}
// This is my strategy
function linkStrategy(contentBlock, callback, contentState) {
    findLinkInText(LINK_REGEX, contentBlock, callback)
}

function findLinkInText(regex, contentBlock, callback) {
    const text = contentBlock.getText();
    let matchArr, start;
    if ((matchArr = regex.exec(text)) !== null) {
        start = matchArr.index;
        let URL = matchArr[0];
        console.log(URL);
        axios.post('/url', {
            url: URL
        }).then(response => {
            passit = response.data
            //not working
            callback(start, start + URL.length)
        })
        //working
        callback(start, start + URL.length)
    }
}
Run Code Online (Sandbox Code Playgroud)

如果回调不起作用,组件将不会呈现..我不知道这是一个基本的JavaScript问题.但问题是我想从我的服务器获取url数据,我必须通过props将数据传递给我的组件并进行渲染.

答案的最新消息

function findLinkInText(regex, contentBlock, callback) {
    const text = contentBlock.getText();
    let matchArr, start;
    if ((matchArr = regex.exec(text)) !== null) {
        start = matchArr.index;
        let url = matchArr[0];
        axios.post('/url', {
            url: URL
        }).then(response => {
            passit = response.data
            handleWithAxiosCallBack(start, start + matchArr[0].length, callback)
        }).catch(err => console.log(err))
    }
}


function handleWithAxiosCallBack(start, startLength, callback) {
    console.log(callback); //Spits out the function But Not working
    callback(start, startLength)
}
Run Code Online (Sandbox Code Playgroud)

Pan*_*her 1

下面描述的技术将帮助您实现您期望的行为。

为什么您的解决方案不起作用:需要执行的所需操作callback未执行的原因是,draft期望callback被称为同步。由于您正在使用一个async函数(axios api 调用)并且异步调用callback没有效果。

解决方案:这可能不是一个有效的解决方案,但可以完成工作。简而言之,您所要做的就是将调用结果存储axios在变量中(临时),然后触发re-render您的editor,提前检索结果存储并使用它来调用回调。

我根据这里的示例进行跟踪。假设您将编辑器状态存储在组件的状态中。下面是一个伪代码,您可能需要根据您的需要来实现。

让我们假设您的组件状态如下所示,它保存Editor的状态。

constructor(props){
 super(props);
 // .. your composite decorators

 // this is your component state holding editors state
 this.state = {
  editorState: EditorState.createWithContent(..)
 }

 // use this to temporarily store the results from axios.
 this.tempResults = {}; 

}
Run Code Online (Sandbox Code Playgroud)

假设您将其渲染Editor为如下所示。注意ref. 这里,编辑器引用存储在组件的editor变量中,您稍后可以访问该变量。使用字符串作为引用可以,但这是存储引用的推荐方法。

 <Editor
    ref={ (editor) => this.editor }
    editorState={this.state.editorState}
    onChange={this.onChange}
    // ...your props
 />
Run Code Online (Sandbox Code Playgroud)

在您的组件中,编写一个函数来使用 currentState 更新编辑器,这将强制re-render. 确保此函数绑定到您的组件,以便我们获得正确的this(上下文)。

forceRenderEditor = () => {
  this.editor.update(this.state.editorState);
}
Run Code Online (Sandbox Code Playgroud)

在您的findLinkInText函数中执行以下操作。

首先确保它(findLinkInText)绑定到您的组件,以便我们获得正确的this. 您可以使用箭头函数来执行此操作或将其绑定在组件构造函数中。

其次,检查我们是否有在组件构造函数中声明的url已结果。tempResults如果我们有一个,则立即使用适当的参数调用回调。

如果我们还没有结果,则进行调用并将结果存储在tempResults. 存储后,调用已经定义的this.forceRenderEditor方法,该方法将调用草稿来重新检查,这一次,由于我们已将结果存储在 中tempResults,因此将调用回调并反映适当的更改。

function findLinkInText(regex, contentBlock, callback) {
 const text = contentBlock.getText();
 let matchArr, start;
 if ((matchArr = regex.exec(text)) !== null) {
     start = matchArr.index;
     let URL = matchArr[0];
     console.log(URL);

     // do we have the result already,?? 
     // call the callback based on the result.
     if(this.tempResults[url]) {
         // make the computations and call the callback() with necessary args
     } else {
     // if we don't have a result, call the api
      axios.post('/url', {
         url: URL
      }).then(response => {
         this.tempResults[url] = response.data;
         this.forceRenderEditor();
         // store the result in this.tempResults and 
         // then call the this.forceRenderEditor
         // You might need to debounce the forceRenderEditor function
      })
    }
 }
}
Run Code Online (Sandbox Code Playgroud)

笔记:

  1. 您必须确定是否需要清除 tempResults。如果是这样,您需要在适当的位置实现它的逻辑。
  2. 要存储 tempResults,您可以使用称为 的技术memoization。上面描述的是一种简单的。
  3. axios api由于您的结果是记忆的,如果调用结果不会因相同的输入而改变,这可能对您来说是一个优势。对于同一查询,您可能不必再次访问 api。
  4. 您存储在 tempResults 中的数据应该是 api 调用的响应,或者您可以从中确定需要传递给 的参数的数据callback
  5. 我认为,如果每个渲染调用了许多 api,您可能需要debounce该方法来避免重复更新。forceRenderEditor
  6. 最后,我找不到draft使用或建议async回调的地方。您可能需要咨询图书馆团队是否支持/需要此类功能。(如果需要,请进行更改,如果他们的团队同意的话,请提出 PR。)

更新

要绑定,您可以移动组件内的函数并按以下方式编写。

linkStrategy = (contentBlock, callback, contentState) => {
    this.findLinkInText(LINK_REGEX, contentBlock, callback)
}


findLinkInText = (...args) => {
}
Run Code Online (Sandbox Code Playgroud)

在你的构造函数中你可以这样调用它

const compositeDecorator = new CompositeDecorator([
    .... {
        strategy: this.linkStrategy,
        component: decorateComponentWithProps(linkComp, {
            passit
        })
    }
    ....
 ]);
}
Run Code Online (Sandbox Code Playgroud)

或者,如果您想跨多个组件重用该函数,则可以通过以下方式绑定它。state但请确保在所有共享组件中使用相同的组件(或使用回调来定义自定义状态)

你的构造函数会像

const compositeDecorator = new CompositeDecorator([
    .... {
        strategy: linkStrategy.bind(this),
        component: decorateComponentWithProps(linkComp, {
            passit
        })
    }
    ....
 ]);
}
Run Code Online (Sandbox Code Playgroud)

你的链接策略将是这样的

 function linkStrategy(contentBlock, callback, contentState) {
    findLinkInText.call(this,LINK_REGEX, contentBlock, callback);
 }
Run Code Online (Sandbox Code Playgroud)

您可以使用上述任一方法来绑定您的函数。