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

时间:2017-04-15 16:09:20

标签: javascript ajax reactjs axios draftjs

我正在尝试使用草稿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)
    }
}

如果回调不起作用,组件将不会呈现.. 我不知道这是一个基本的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)
}

3 个答案:

答案 0 :(得分:1)

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

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

解决方案:这可能不是一种有效的解决方案,但可以完成工作。简单来说,您所要做的就是将callback调用的结果存储在变量中(暂时),然后触发axios的{​​{1}},之前检索结果存储并用它来调用回调。

我正在根据此示例here进行关注。假设您将编辑器状态存储在组件的状态中。以下是您可能需要根据需要实施的伪代码。

让我们假设您的组件状态如下所示,它保存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 = {}; } 。编辑器引用存储在组件的Editor变量中,您可以稍后访问该变量。使用字符串作为ref会起作用,但这是存储引用的推荐方法。

ref

在你的组件中,编写一个函数来使用currentState更新编辑器,这会强制editor。确保此函数绑定到您的组件,以便我们获得正确的 <Editor ref={ (editor) => this.editor } editorState={this.state.editorState} onChange={this.onChange} // ...your props /> (上下文)。

re-render

this功能中执行以下操作。

首先确保它(findLinkInText)绑定到您的组件,以便我们得到正确的forceRenderEditor = () => { this.editor.update(this.state.editorState); } 。您可以使用箭头函数执行此操作或将其绑定到组件构造函数中。

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

如果我们还没有结果,请拨打电话并将结果存储在url中。存储之后,调用已定义的tempResults方法,该方法将调用草稿进行重新检查,这次,由于我们已将结果存储在tempResults中,因此将调用回调并反映相应的更改。

this.forceRenderEditor

注意:

  1. 您必须确定是否需要清除tempResults。如果是这样,你需要在适当的地方为它实现逻辑。
  2. 要存储tempResults,您可以使用名为tempResults的技术。上面描述的是一个简单的。
  3. 由于您的结果已被记录,如果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 }) } } } 调用结果不会针对相同的输入进行更改,则这可能对您有利。对于同一个查询,您可能不必再次点击api。
  4. 您存储在tempResults中的数据应该是来自api调用的响应,或者您可以从中确定需要传递给memoization的参数的内容。
  5. 我认为,如果为每个渲染调用了很多api,您可能需要axios api callback方法以避免重复更新。
  6. 最后,我找不到debounce使用或建议用于forceRenderEditor回调的地方。如果他们支持/需要这样的功能,您可能需要向图书馆的团队查询。 (如果需要进行更改并提高公关,如果他们的团队合适则可以。)
  7. <强>更新

    要进行绑定,您可以移动组件中的函数并以下面的方式编写它。

    draft

    在构造函数中,您可以像这样调用它

    async

    或者,如果您想在多个组件中重用该功能,则可以按以下方式绑定它。但请确保在所有共享组件中使用相同的linkStrategy = (contentBlock, callback, contentState) => { this.findLinkInText(LINK_REGEX, contentBlock, callback) } findLinkInText = (...args) => { } (或使用回调来定义自定义状态)

    你的构造函数就像

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

    您的链接策略将是这样的

    state

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

答案 1 :(得分:-1)

假设其他一切正常,我会期待下面的更多内容。我没有设置使用Axios,因此我无法对此进行测试。

// I made these global variables because you are trying to use them
// in both the .post and the .then
var start; // global variable
var URL // global variable
function processResponse (aStart, aStartURL, passit) {
    // do something with the reponse data
}

function findLinkInText(regex, contentBlock) {
    const text = contentBlock.getText();
    let matchArr;
    if((matchArr = regex.exec(text)) !== null){
        start = matchArr.index;
        // renamed because it is not the url, its data passed to the server
        URL = matchArr[0];
        console.log(URL);
        axios.post('/url',{url:URL}).then(response => {
            passit = response.data;
            processResponse (start, start + URL.length, passit)
        }).catch(function (error) {
            console.log(error);
        });
    }
}

答案 2 :(得分:-1)

请注意,&#34; axios依赖于支持的本机ES6 Promise实现。如果您的环境不支持ES6 Promises,您可以填充。&#34;这意味着这不适用于所有浏览器。 (即使在此处包含推荐的包含https://github.com/stefanpenner/es6-promise

之后,我也无法在IE 11中使用它

这是我在Edge中工作的代码:

const myModule = require('./myModule.js');

由此我相应地更改了您的代码,如下所示

            axios(
                {
                    method: 'post',
                    url: '/wsService.asmx/GetDTDataSerializedList',
                    data: { parameters: 'one' },
                    callback: function () { alert() }
                })
                  .then(response =>{
                      response.config.callback();

                      console.log(response);
                  })
                  .catch(function (error) {
                      console.log(error);
                  });
             });