Callback not working in ajax request?

I am trying to create a contentEditor using a js project. This function is to extract data from a URL, such as Facebook. But I am stuck with this part. Callback does not work.

First I wrapped my state with compositeDecorator Like this

 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) } } 

If the callback does not work, the component will not be displayed. I do not know that this is the main problem with JavaScript. But I want to get url data from my server, and I have to transfer the data through the details to my component and make it.

UPDATE ANSWERS

 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) } 
+5
source share
3 answers

The following method will help you achieve your expected behavior.

Why your solution doesn’t work: The reason why the required action that should be performed using callback is not executed is because draft expects the callback be called synchronous, since you are using the async function (calling axios api) and calling asynchronously callback , it does not affect.

Solution: This may not be an effective solution, but it can be implemented. Simply put, all you have to do is save the results of the axios call in a variable (temporarily) and then run re-render for your editor , first get the results store and use it to call the callback.

I follow this example here . Assuming you keep the editor state in component state. Below is the pseudo code that you may need to implement according to your needs.

Suppose your component state seems lower than the editor state.

 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 = {}; } 

Assuming you pass your editor to something like below. Pay attention to ref . Here the link of the editors is stored in the editor variable of the component, which you can access later. Using a string like ref will work, but this is the recommended way to store links.

  <Editor ref={ (editor) => this.editor } editorState={this.state.editorState} onChange={this.onChange} // ...your props /> 

In your component, write a function to update the editor using currentState, which will force re-render . Make sure that this function is bound to your component so that we get the correct this (context).

 forceRenderEditor = () => { this.editor.update(this.state.editorState); } 

In your findLinkInText function findLinkInText do the following.

First make sure that it (findLinkInText) is bound to your component, so we get the correct this . You can use the arrow function to do this or link it in the component constructor.

Secondly, check if the result for url already in tempResults which we declared in the component constructor. If we have one, then call the callback immediately with the appropriate arguments.

If we don’t already have a result, make a call and save the result in tempResults . After saving, call the already defined method this.forceRenderEditor , which will call a draft for re-checking, and this time, since we saved the results in tempResults , a tempResults will be called and the corresponding changes will be reflected.

 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 }) } } } 

Note:

  • You need to determine whether to clear tempResults. If so, you need to implement the logic for it in the appropriate place.
  • To save tempResults, you can use a technique called memoization . The above is one simple.
  • Since your results are noticed, this may be an advantage for you if the results of invoking the axios api do not change for the same input. You may not have to hit the api again for the same request.
  • The data stored in your tempResults should be the response from an api call or something from which you can determine the arguments you need to pass to the callback .
  • It seems to me that you might need the debounce forceRenderEditor method to avoid re-updating if a lot of api is called for each rendering.
  • Finally, I could not find a place where draft uses or suggests async call back. You may need to consult the library team if they support / need such a function. (If necessary, make changes and raise the PR, if their team is in order with one.)

Update

To bind, you can move functions inside the component and write it below.

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

And in your constructor you can call it like this

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

Or, if you want to reuse a function for multiple components, you can bind it below. But remember to use the same state in all sharing components (or use a callback to define user states)

Your constructor will look like

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

Your link strategy will be like this:

  function linkStrategy(contentBlock, callback, contentState) { findLinkInText.call(this,LINK_REGEX, contentBlock, callback); } 

You can use any of the above methods to bind your functions.

+1
source

Assuming everything else works, I expect something more that is lower. I am not configured to use Axios, so I cannot verify this.

 // 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); }); } } 
-1
source

Please note that "axios depends on support for the on-board ES6 Promise. If your environment does not support ES6 Promises, you can polyfill." which means that this does not work in all browsers. (I could not get it to work in IE 11, even after enabling the recommended here, enable https://github.com/stefanpenner/es6-promise

Here is my code I got in Edge:

  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); }); }); 

With this, I changed your code accordingly as shown below

  function findLinkInText(regex, contentBlock, callback) { const text = contentBlock.getText(); let matchArr, start; if ((matchArr = regex.exec(text)) !== null) { start = matchArr.index; var URL = matchArr[0]; console.log(URL); // I am putting the parameters used to make the call in a JSON object to be used in the "then" var myparameters = { myCallback: callback, URL: URL, start: start }; axios({ method:post, url:'/url', data: { url: URL }, // note that i am attaching the callback to be carrired through myParameters: myparameters }).then(response => { // This section is the callback generated by the post request. // it cannot see anything unless they declared globally or attached to the request and passed through // which is what i did. passit = response.data var s = response.config.myParameters.start; var u = response.config.myParameters.URL response.config.myParameters.myCallback(s, s + u.length) }) } } 
-1
source

Source: https://habr.com/ru/post/1266766/


All Articles