回调在 ajax 请求中不起作用?
Callback is not working in ajax request?
我正在尝试使用 draft js 构建一个 contentEditor。确切地说,该功能是从 url 中提取数据,例如 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)
}
假设其他一切正常,我会期待下面的内容。我没有设置为使用 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);
});
}
}
请注意 "axios depends on a native ES6 Promise implementation to be supported. If your environment doesn't support ES6 Promises, you can polyfill." 这意味着这不适用于所有浏览器。 (即使在此处包含推荐的 include https://github.com/stefanpenner/es6-promise
后,我也无法在 IE 11 中使用它
这是我在 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);
});
});
然后我相应地更改了您的代码,如下所示
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)
})
}
}
下面描述的技术将帮助您实现您期望的行为。
为什么您的解决方案不起作用: callback
需要执行的所需操作没有执行的原因是,draft
期望 callback
被称为同步。由于您使用的是 async
函数(axios api 调用)并且异步调用 callback
无效。
解决方案:这可能不是一个有效的解决方案,但可以完成工作。简而言之,您所要做的就是将 axios
调用的结果存储在一个变量中(临时),然后为您的 editor
触发 re-render
,更早地检索结果存储并用它来调用回调。
我是根据这个例子here 来跟进的。假设您将编辑器状态存储在组件的状态中。以下是您可能需要根据需要实施的伪代码。
让我们假设您的组件状态如下所示,其中包含 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
。此处编辑器引用存储在组件的 editor
变量中,您可以稍后访问该变量。使用字符串作为 ref 是可行的,但这是存储 refs 的推荐方式。
<Editor
ref={ (editor) => this.editor }
editorState={this.state.editorState}
onChange={this.onChange}
// ...your props
/>
在您的组件中,编写一个函数以使用 currentState 更新编辑器,这将强制 re-render
。确保此函数已绑定到您的组件,以便我们获得正确的 this
(context).
forceRenderEditor = () => {
this.editor.update(this.state.editorState);
}
在您的 findLinkInText
函数中执行以下操作。
首先确保它 (findLinkInText) 绑定到您的组件,以便我们得到正确的 this
。您可以使用箭头函数来执行此操作或将其绑定到组件构造函数中。
其次,检查 url
的结果是否已经在 tempResults
中
我们在组件的构造函数中声明的。如果我们有,则立即使用适当的参数调用回调。
如果我们还没有结果,请调用并将结果存储在 tempResults
中。存储后,调用已经定义的 this.forceRenderEditor
方法,该方法将调用 draft 重新检查,这一次,因为我们已经将结果存储在 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
})
}
}
}
注:
- 您必须确定是否需要清除临时结果。如果是这样,您需要在适当的地方实现它的逻辑。
- 要存储临时结果,您可以使用称为
memoization
的技术。上面描述的是一个简单的。
- 由于您的结果已存储,如果
axios api
调用结果不会因相同的输入而改变,这对您来说可能是一个优势。对于同一个查询,您可能不必再次点击 api。
- 您存储在 tempResults 中的数据应该是 api 调用的响应,或者您可以从中确定需要传递给
callback
的参数的内容。
- 我认为,如果每个渲染调用很多 api,您可能需要
debounce
forceRenderEditor
方法来避免重复更新。
- 最后,我找不到
draft
使用或建议 async
回调的地方。如果他们 support/need 这样的功能,您可能需要咨询图书馆的团队。 (如果需要,如果他们的团队同意,则进行更改并提出 PR。)
更新
要绑定,您可以在组件内移动函数并按以下方式编写。
linkStrategy = (contentBlock, callback, contentState) => {
this.findLinkInText(LINK_REGEX, contentBlock, callback)
}
findLinkInText = (...args) => {
}
在你的构造函数中你可以这样调用它
const compositeDecorator = new CompositeDecorator([
.... {
strategy: this.linkStrategy,
component: decorateComponentWithProps(linkComp, {
passit
})
}
....
]);
}
或者如果您想跨多个组件重用该功能,则可以通过以下方式绑定它。但请确保在所有共享组件中使用相同的 state
(或使用回调来定义自定义状态)
你的构造函数会像
const compositeDecorator = new CompositeDecorator([
.... {
strategy: linkStrategy.bind(this),
component: decorateComponentWithProps(linkComp, {
passit
})
}
....
]);
}
你的link策略会是这样
function linkStrategy(contentBlock, callback, contentState) {
findLinkInText.call(this,LINK_REGEX, contentBlock, callback);
}
您可以使用上述任何一种方法来绑定您的函数。
我正在尝试使用 draft js 构建一个 contentEditor。确切地说,该功能是从 url 中提取数据,例如 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)
}
假设其他一切正常,我会期待下面的内容。我没有设置为使用 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);
});
}
}
请注意 "axios depends on a native ES6 Promise implementation to be supported. If your environment doesn't support ES6 Promises, you can polyfill." 这意味着这不适用于所有浏览器。 (即使在此处包含推荐的 include https://github.com/stefanpenner/es6-promise
后,我也无法在 IE 11 中使用它这是我在 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);
});
});
然后我相应地更改了您的代码,如下所示
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)
})
}
}
下面描述的技术将帮助您实现您期望的行为。
为什么您的解决方案不起作用: callback
需要执行的所需操作没有执行的原因是,draft
期望 callback
被称为同步。由于您使用的是 async
函数(axios api 调用)并且异步调用 callback
无效。
解决方案:这可能不是一个有效的解决方案,但可以完成工作。简而言之,您所要做的就是将 axios
调用的结果存储在一个变量中(临时),然后为您的 editor
触发 re-render
,更早地检索结果存储并用它来调用回调。
我是根据这个例子here 来跟进的。假设您将编辑器状态存储在组件的状态中。以下是您可能需要根据需要实施的伪代码。
让我们假设您的组件状态如下所示,其中包含 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
。此处编辑器引用存储在组件的 editor
变量中,您可以稍后访问该变量。使用字符串作为 ref 是可行的,但这是存储 refs 的推荐方式。
<Editor
ref={ (editor) => this.editor }
editorState={this.state.editorState}
onChange={this.onChange}
// ...your props
/>
在您的组件中,编写一个函数以使用 currentState 更新编辑器,这将强制 re-render
。确保此函数已绑定到您的组件,以便我们获得正确的 this
(context).
forceRenderEditor = () => {
this.editor.update(this.state.editorState);
}
在您的 findLinkInText
函数中执行以下操作。
首先确保它 (findLinkInText) 绑定到您的组件,以便我们得到正确的 this
。您可以使用箭头函数来执行此操作或将其绑定到组件构造函数中。
其次,检查 url
的结果是否已经在 tempResults
中
我们在组件的构造函数中声明的。如果我们有,则立即使用适当的参数调用回调。
如果我们还没有结果,请调用并将结果存储在 tempResults
中。存储后,调用已经定义的 this.forceRenderEditor
方法,该方法将调用 draft 重新检查,这一次,因为我们已经将结果存储在 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
})
}
}
}
注:
- 您必须确定是否需要清除临时结果。如果是这样,您需要在适当的地方实现它的逻辑。
- 要存储临时结果,您可以使用称为
memoization
的技术。上面描述的是一个简单的。 - 由于您的结果已存储,如果
axios api
调用结果不会因相同的输入而改变,这对您来说可能是一个优势。对于同一个查询,您可能不必再次点击 api。 - 您存储在 tempResults 中的数据应该是 api 调用的响应,或者您可以从中确定需要传递给
callback
的参数的内容。 - 我认为,如果每个渲染调用很多 api,您可能需要
debounce
forceRenderEditor
方法来避免重复更新。 - 最后,我找不到
draft
使用或建议async
回调的地方。如果他们 support/need 这样的功能,您可能需要咨询图书馆的团队。 (如果需要,如果他们的团队同意,则进行更改并提出 PR。)
更新
要绑定,您可以在组件内移动函数并按以下方式编写。
linkStrategy = (contentBlock, callback, contentState) => {
this.findLinkInText(LINK_REGEX, contentBlock, callback)
}
findLinkInText = (...args) => {
}
在你的构造函数中你可以这样调用它
const compositeDecorator = new CompositeDecorator([
.... {
strategy: this.linkStrategy,
component: decorateComponentWithProps(linkComp, {
passit
})
}
....
]);
}
或者如果您想跨多个组件重用该功能,则可以通过以下方式绑定它。但请确保在所有共享组件中使用相同的 state
(或使用回调来定义自定义状态)
你的构造函数会像
const compositeDecorator = new CompositeDecorator([
.... {
strategy: linkStrategy.bind(this),
component: decorateComponentWithProps(linkComp, {
passit
})
}
....
]);
}
你的link策略会是这样
function linkStrategy(contentBlock, callback, contentState) {
findLinkInText.call(this,LINK_REGEX, contentBlock, callback);
}
您可以使用上述任何一种方法来绑定您的函数。