存储来自 Axios Promise 的数据以供多种用途
Storing data from Axios Promise for multiple uses
我已经在 express 中创建了一个处理 get 请求的端点。从反应组件中,我使用 axios 向所述端点发出获取请求。我想将数据存储在我的组件 class 中的一个对象中,以便可以多次访问它(onComponentDidLoad、多个 onClick 事件处理程序等)。有没有办法在 axios promise 之外存储数据,and/or 保留 promise 以便我可以执行多个 .then 调用而不履行 promise?
我试过使用 setState(),返回 promise,并从 get 请求中返回实际数据。
这是我现在拥有的:
constructor {
super();
this.myData = [];
this.getData = this.getData.bind(this);
this.storeData = this.storeData.bind(this);
this.showData = this.showData.bind(this);
}
// Store data
storeData = (data) => {this.myData.push(data)};
// Get data from API
getData() {
axios
.get('/someEndpoint')
.then(response => {
let body = response['data'];
if(body) {
this.storeData(body);
}
})
.catch(function(error) {
console.log(error);
});
}
showData() {
console.log(this.myData.length); // Always results in '0'
}
componentDidMount = () => {
this.getData(); // Get data
this.showData(); // Show Data
}
render() {
return(
<Button onClick={this.showData}> Show Data </Button>
);
}
编辑
我的问题不正确,存储承诺然后进行多次 .then 调用是可行的。我试的时候格式错了
如果您只是将 promise 存储在本地并将其作为 promise 进行访问,它应该可以正常工作。
getData() {
// if request has already been made then just return the previous request.
this.data = this.data || axios.get(url)
.then( response => response.data)
.catch(console.log)
return this.data
}
showData() {
this.getData().then(d => console.log('my data is', data));
}
此代码无法正常工作,因为您试图在不等待数据解析的情况下显示数据:
componentDidMount = () => {
this.getData();
this.showData();
}
正如您在原始 post 中暗示的那样,您需要从 Promise 中提取数据,但无法以同步方式执行此操作。您可以做的第一件事就是简单地存储原始 Promise 并在需要时访问它 - Promise 可以 then()
ed 多次:
class C extends React.Component {
state = {
promise: Promise.reject("not yet ready")
};
showData = async () => {
// You can now re-use this.state.promise.
// The caveat here is that you might potentially wait forever for a promise to resolve.
console.log(await this.state.promise);
}
componentDidMount() {
const t = fetchData();
this.setState({ promise: t });
// Take care not to re-assign here this.state.promise here, as otherwise
// subsequent calls to t.then() will have the return value of showData() (undefined)
// instead of the data you want.
t.then(() => this.showData());
}
render() {
const handleClick = () => {
this.showData();
};
return <button onClick={handleClick}>Click Me</button>;
}
}
另一种方法是通过将异步完全限制在 fetchData() 函数来尝试使您的组件尽可能保持同步,这可能会使您的组件更容易推理:
class C extends React.Component {
state = {
status: "pending",
data: undefined
};
async fetchData(abortSignal) {
this.setState({ status: "pending" });
try {
const response = await fetch(..., { signal: abortSignal });
const data = await response.json();
this.setState({ data: data, status: "ok" });
} catch (err) {
this.setState({ error: err, status: "error" });
} finally {
this.setState({ status: "pending" });
}
}
showData() {
// Note how we now do not need to pollute showData() with asyncrony
switch (this.state.status) {
case "pending":
...
case "ok":
console.log(this.state.data);
case "error":
...
}
}
componentDidMount() {
// Using an instance property is analogous to using a ref in React Hooks.
// We don't want this to be state because we don't want the component to update when the abort controller changes.
this.abortCtrl = new AbortController();
this.fetchData(this.abortCtrl.signal);
}
componentDidUnmount() {
this.abortCtrl.abort();
}
render() {
return <button onClick={() => this.showData()}>Click Me</button>
}
}
我已经在 express 中创建了一个处理 get 请求的端点。从反应组件中,我使用 axios 向所述端点发出获取请求。我想将数据存储在我的组件 class 中的一个对象中,以便可以多次访问它(onComponentDidLoad、多个 onClick 事件处理程序等)。有没有办法在 axios promise 之外存储数据,and/or 保留 promise 以便我可以执行多个 .then 调用而不履行 promise?
我试过使用 setState(),返回 promise,并从 get 请求中返回实际数据。
这是我现在拥有的:
constructor {
super();
this.myData = [];
this.getData = this.getData.bind(this);
this.storeData = this.storeData.bind(this);
this.showData = this.showData.bind(this);
}
// Store data
storeData = (data) => {this.myData.push(data)};
// Get data from API
getData() {
axios
.get('/someEndpoint')
.then(response => {
let body = response['data'];
if(body) {
this.storeData(body);
}
})
.catch(function(error) {
console.log(error);
});
}
showData() {
console.log(this.myData.length); // Always results in '0'
}
componentDidMount = () => {
this.getData(); // Get data
this.showData(); // Show Data
}
render() {
return(
<Button onClick={this.showData}> Show Data </Button>
);
}
编辑 我的问题不正确,存储承诺然后进行多次 .then 调用是可行的。我试的时候格式错了
如果您只是将 promise 存储在本地并将其作为 promise 进行访问,它应该可以正常工作。
getData() {
// if request has already been made then just return the previous request.
this.data = this.data || axios.get(url)
.then( response => response.data)
.catch(console.log)
return this.data
}
showData() {
this.getData().then(d => console.log('my data is', data));
}
此代码无法正常工作,因为您试图在不等待数据解析的情况下显示数据:
componentDidMount = () => {
this.getData();
this.showData();
}
正如您在原始 post 中暗示的那样,您需要从 Promise 中提取数据,但无法以同步方式执行此操作。您可以做的第一件事就是简单地存储原始 Promise 并在需要时访问它 - Promise 可以 then()
ed 多次:
class C extends React.Component {
state = {
promise: Promise.reject("not yet ready")
};
showData = async () => {
// You can now re-use this.state.promise.
// The caveat here is that you might potentially wait forever for a promise to resolve.
console.log(await this.state.promise);
}
componentDidMount() {
const t = fetchData();
this.setState({ promise: t });
// Take care not to re-assign here this.state.promise here, as otherwise
// subsequent calls to t.then() will have the return value of showData() (undefined)
// instead of the data you want.
t.then(() => this.showData());
}
render() {
const handleClick = () => {
this.showData();
};
return <button onClick={handleClick}>Click Me</button>;
}
}
另一种方法是通过将异步完全限制在 fetchData() 函数来尝试使您的组件尽可能保持同步,这可能会使您的组件更容易推理:
class C extends React.Component {
state = {
status: "pending",
data: undefined
};
async fetchData(abortSignal) {
this.setState({ status: "pending" });
try {
const response = await fetch(..., { signal: abortSignal });
const data = await response.json();
this.setState({ data: data, status: "ok" });
} catch (err) {
this.setState({ error: err, status: "error" });
} finally {
this.setState({ status: "pending" });
}
}
showData() {
// Note how we now do not need to pollute showData() with asyncrony
switch (this.state.status) {
case "pending":
...
case "ok":
console.log(this.state.data);
case "error":
...
}
}
componentDidMount() {
// Using an instance property is analogous to using a ref in React Hooks.
// We don't want this to be state because we don't want the component to update when the abort controller changes.
this.abortCtrl = new AbortController();
this.fetchData(this.abortCtrl.signal);
}
componentDidUnmount() {
this.abortCtrl.abort();
}
render() {
return <button onClick={() => this.showData()}>Click Me</button>
}
}