[英]React component not getting rendered with map function
調用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 });
}
在渲染功能中,我使用地圖來渲染每個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進行響應的您可能會有所幫助。
loadAll() {
db.find({ type: "link" }, (err, docs) => { // changed to arrow function
this.setState({ data: docs.map(doc => doc.name)});
});
}
您的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;
檢索文檔后 ,您需要在回調中調用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
聲明為async並使用await :
loadAll() {
const docs = await db.find({ type: "link" });
this.setState({ data: docs.map(doc => doc.name) });
}
順便說一下,有一些技巧可以使您的代碼更短:
最終代碼將如下所示:
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
聲明為箭頭函數,因為render
由React自動綁定 。
讓我知道這是否可行,否則,請告訴我出了什么問題。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.