Render() 状态元素最初为空,直到 api 调用
Render() state element is initially empty until api call
我有一个 class 组件,它应该在 API 调用后显示一些列表值,在我的渲染函数中,我调用一个函数来填充一些其他状态列表(具有来自获取的列表),问题是在渲染调用中,状态值最初是空的,因此组件 I return 也只是空的。
我试过使用 componentDidUpdate() 但我不太清楚如何使用它,它通常会给我一个无限循环。
这是我的相关代码:
class AdminSales extends React.Component {
constructor(props) {
super(props);
this.state = {
items: [],
data: [],
};
}
componentDidMount() {
this.fetchData();
}
fetchData() {
fetch("/api/items")
.then((res) => res.json())
.then((items) => this.setState({ items: items }));
}
componentDidUpdate(prevState) {
if (JSON.stringify(prevState.items) == JSON.stringify(this.state.items)) {
// Do nothing
} else {
// This gives infinite loop ...
// this.fetchData();
}
}
populateData() {
this.state.items.forEach(function (item) {
this.state.data.push({
name: item.name,
value: item.quantity,
});
}, this);
}
render() {
// Output shown line: 65
console.log(this.state);
this.populateData();
const { data } = this.state;
return ( ... );
}
}
export default AdminSales;
任何帮助将不胜感激。
首先你的代码中存在多个问题
- Updating/Mutating 状态
render
- 不是使用
setState
更新状态,而是在 populateData
方法中更新状态
此外,正如@Drew 提到的,我们不必将 items
复制到 data
中,而是在从 API.
在等待响应的同时,如果您想显示加载信息,您也可以这样做。
以下是涵盖上述所有要点的示例。
const mockAPI = () => {
return new Promise((resolve) => setTimeout(() => {
resolve([{id:1, name: "ABC", quantity: 1}, {id: 2, name: "DEF", quantity: 5}, {id: 3, name: "XYZ", quantity: 9}])
}, 500));
}
class AdminSales extends React.Component {
constructor(props) {
super(props);
this.state = {
items: [],
loading: true
};
}
componentDidMount() {
this.fetchData();
}
fetchData = () => {
mockAPI()
.then((res) => {
this.populateData(res);
});
}
populateData = (data) => {
this.setState({
items: data.map(({name, quantity}) => ({
name,
value: quantity
})),
loading: false
})
}
render() {
//console.log(this.state);
const { items, loading } = this.state;
return loading ? <p>Loading...</p> :
items.map(item => (
<div>{item.name}: {item.value}</div>
));
}
}
ReactDOM.render(<AdminSales />, document.getElementById("react"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="react"></div>
Note: For simplicity I've mocked the backend API with simple setTimeout
.
我有一个 class 组件,它应该在 API 调用后显示一些列表值,在我的渲染函数中,我调用一个函数来填充一些其他状态列表(具有来自获取的列表),问题是在渲染调用中,状态值最初是空的,因此组件 I return 也只是空的。
我试过使用 componentDidUpdate() 但我不太清楚如何使用它,它通常会给我一个无限循环。
这是我的相关代码:
class AdminSales extends React.Component {
constructor(props) {
super(props);
this.state = {
items: [],
data: [],
};
}
componentDidMount() {
this.fetchData();
}
fetchData() {
fetch("/api/items")
.then((res) => res.json())
.then((items) => this.setState({ items: items }));
}
componentDidUpdate(prevState) {
if (JSON.stringify(prevState.items) == JSON.stringify(this.state.items)) {
// Do nothing
} else {
// This gives infinite loop ...
// this.fetchData();
}
}
populateData() {
this.state.items.forEach(function (item) {
this.state.data.push({
name: item.name,
value: item.quantity,
});
}, this);
}
render() {
// Output shown line: 65
console.log(this.state);
this.populateData();
const { data } = this.state;
return ( ... );
}
}
export default AdminSales;
任何帮助将不胜感激。
首先你的代码中存在多个问题
- Updating/Mutating 状态
render
- 不是使用
setState
更新状态,而是在populateData
方法中更新状态
此外,正如@Drew 提到的,我们不必将 items
复制到 data
中,而是在从 API.
在等待响应的同时,如果您想显示加载信息,您也可以这样做。
以下是涵盖上述所有要点的示例。
const mockAPI = () => {
return new Promise((resolve) => setTimeout(() => {
resolve([{id:1, name: "ABC", quantity: 1}, {id: 2, name: "DEF", quantity: 5}, {id: 3, name: "XYZ", quantity: 9}])
}, 500));
}
class AdminSales extends React.Component {
constructor(props) {
super(props);
this.state = {
items: [],
loading: true
};
}
componentDidMount() {
this.fetchData();
}
fetchData = () => {
mockAPI()
.then((res) => {
this.populateData(res);
});
}
populateData = (data) => {
this.setState({
items: data.map(({name, quantity}) => ({
name,
value: quantity
})),
loading: false
})
}
render() {
//console.log(this.state);
const { items, loading } = this.state;
return loading ? <p>Loading...</p> :
items.map(item => (
<div>{item.name}: {item.value}</div>
));
}
}
ReactDOM.render(<AdminSales />, document.getElementById("react"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="react"></div>
Note: For simplicity I've mocked the backend API with simple
setTimeout
.