调用loadAll()时,不会呈现我的LinkItem组件。仅在handleClick()或handleChange()被调用后才呈现。
import React, { Component } from "react";
var Datastore = require("nedb");
var db = new Datastore({ filename: __dirname + "/userdata" });
db.loadDatabase(function(err) {
});
function LinkItem(props) {
console.log("Rendered");
return (
<div>
<a href={props.name}>{props.name}</a>
</div>
);
}
export default class List extends Component {
constructor(props) {
super(props);
this.state = {
link: "",
data: [],
};
this.handleClick = this.handleClick.bind(this);
this.handleChange = this.handleChange.bind(this);
this.loadAll = this.loadAll.bind(this);
}
loadAll() {
let loadData = [];
db.find({ type: "link" }, function(err, docs) {
docs.map(doc => loadData.push(doc.name));
});
this.setState({ data: loadData });
}
// add new item to data set
handleClick() {
this.setState({
data: [...this.state.data, this.state.link]
});
const doc = { name: this.state.link, type: "link" };
db.insert(doc, (err, docs) => {
console.log("Inserted");
console.log(docs);
});
}
// handles form input changes
handleChange(event) {
this.setState({ link: event.target.value });
}
在render函数中,我正在使用map渲染每个LinkItem组件。但是,当我在LinkItem组件上检查console.log时,根本不会创建它们。它们仅在handleClick和调用handleChange时出现。
render() {
const data = this.state.data;
return (
<div>
<button onClick={this.loadAll}>Load data</button>
<input
type="text"
value={this.state.link}
onChange={this.handleChange}
/>
<button onClick={this.handleClick}>Add</button>
{console.log(data)}
{/* render each data */}
{data.map((item, index) => (
<LinkItem name={item} key={index} />
))}
</div>
);
}
}
基本上我想发生的是调用loadData时,所有数据都呈现在LinkItem组件中。
注意:这不是重复项。我检查了stackoverflow中的其他问题,这些问题在map函数中没有返回。对我来说不是这样。只有在其他状态值更改时,它才最终呈现。
编辑:我可以通过将setState放在db find中并将回调更改为箭头函数来修复它。对于使用nedb和react的人来说,这可能有所帮助。
loadAll() {
db.find({ type: "link" }, (err, docs) => { // changed to arrow function
this.setState({ data: docs.map(doc => doc.name)});
});
}
答案 0 :(得分:2)
您的db.find
函数是异步的,您的程序将继续运行,而无需等待它完成:
loadAll() {
let loadData = [];
db.find({ type: "link" }, function(err, docs) {
docs.map(doc => loadData.push(doc.name));
});
this.setState({ data: loadData });
}
您有2种解决方案来解决它。
将setState
放入回调中:
loadAll() {
let loadData = [];
db.find({ type: "link" }, function(err, docs) {
docs.map(doc => loadData.push(doc.name));
this.setState({ data: loadData });
});
}
或等待您的通话:
loadAll = async() => {
let loadData = [];
const docs = await db.find({ type: "link" });
docs.map(doc => loadData.push(doc.name));
this.setState({ data: loadData });
}
此外,map函数还将返回一个包含您的值的新数组。以下语法较短,并且具有相同的作用:
loadAll = async () => {
this.setState({
data: (await db.find({ type: "link" })).map(doc => doc.name)
});
}
我还注意到您在setState
中使用了状态值。 React建议在回调中使用您之前的状态来避免发生意外行为:
handleClick() {
this.setState(prevState => {
data: [...prevState.data, prevState.link]
});
您可以使用的另一种方法是解构,此代码:
const data = this.state.data;
可能会变成:
const { data } = this.state;
答案 1 :(得分:1)
您需要在回调中,在获取文件后调用setState
:
loadAll() {
let loadData = [];
db.find({ type: "link" }, function(err, docs) {
docs.map(doc => loadData.push(doc.name));
this.setState({ data: loadData });
});
}
或者只是做
loadAll() {
db.find({ type: "link" }, function(err, docs) {
this.setState({ data: docs.map(doc => doc.name)});
});
}
您必须这样做的原因是因为db.find
是异步函数,所以它将立即返回,因此loadData
等于[]
。
您还可以将loadAll
声明为异步并使用 await :
loadAll() {
const docs = await db.find({ type: "link" });
this.setState({ data: docs.map(doc => doc.name) });
}
顺便说一句,有一些技巧可以使您的代码更简短:
state
,则可以摆脱构造函数的作用最终代码将如下所示:
import React, { Component } from "react";
var Datastore = require("nedb");
var db = new Datastore({ filename: __dirname + "/userdata" });
db.loadDatabase(function(err) {
});
function LinkItem(props) {
console.log("Rendered");
return (
<div>
<a href={props.name}>{props.name}</a>
</div>
);
}
export default class List extends Component {
state = {
link: "",
data: [],
}
loadAll = async () => {
const docs = await db.find({ type: "link" });
this.setState({ data: docs.map(doc => doc.name) });
}
// add new item to data set
handleClick = () => {
const { data, link } = this.state;
this.setState({
data: [...data, link]
});
const doc = { name: this.state.link, type: "link" };
db.insert(doc, (err, docs) => {
console.log("Inserted");
console.log(docs);
});
}
// handles form input changes
handleChange = (event) => {
this.setState({ link: event.target.value });
}
render() {
const { data } = this.state;
return (
<div>
<button onClick={this.loadAll}>Load data</button>
<input
type="text"
value={this.state.link}
onChange={this.handleChange}
/>
<button onClick={this.handleClick}>Add</button>
{console.log(data)}
{/* render each data */}
{data.map((item, index) => (
<LinkItem name={item} key={index} />
))}
</div>
);
}
}
请注意,render
不需要声明为箭头功能,因为它是由React自动绑定的。
让我知道这是否可行,否则,请告诉我出了什么问题。