我已经习惯了一段时间的API,创建了我自己的书籍API来练习。我已经使用html和JavaScript-ES6创建了一个完整的函数库,所有Ajax请求都正常工作。我继续研究Reactjs并尝试使用React构建相同的库。因此,在处理API时,我听说fetch是首选。 所以这是我使用fetch的GET请求:
fetch('http://localhost:8000/api/Books')
.then(response => {
if (!response.ok) {
throw Error('Network request failed.')
}
return response;
})
.then(data => data.json())
.then(data => {
let output = ''
for (let book of data) {
output += (
<Book id={book._id}
title={book.title}
author={book.author}
genre={book.genre}
read={book.read} />
);
}
console.log('parsed json', data);
document.getElementById('database').innerHTML = output;
}, (ex) => {
this.setState({
requestError : true
});
console.log('parsing failed', ex)
})
正如您所看到的,Book组件就是将信息作为props获取,并且是父“LibraryProject”组件的子组件。书看起来像这样:
class Book extends React.Component{
constructor (props){
super(props);
this.state = {
edit : false
}
}
render() {
return (
<li data-id={this.props.id}>
<p><span className="noedit title">{this.props.title}</span>
<input type="text" className="edit title"/>
</p>
<p>Author: <span className="noedit author">{this.props.author}</span>
<input type="text" className="edit author"/>
</p>
<p>Genre: <span className="noedit genre">{this.props.genre}</span>
<input type="text" className="edit genre"/></p>
<p>Read: <span className="noedit read">{this.props.read?"Yes":"No"}</span>
<input type="checkbox"
className="edit read"
value={this.props.read?"true":"false"}/>
</p>
<button data-id={this.props.id} className='remove'>Delete</button>
<button className="editBook noedit">Edit</button>
<button className="saveEdit edit">Save</button>
<button className="cancelEdit edit">Cancel</button>
</li>
)
}}
预计会有编辑和删除功能,因此它的结构。
现在,当用户单击按钮时进行调用,因此不使用componentDidMount或任何其他生命周期,请求只是在handleClick函数中实现。
如您所见,我在console.log中请求数据。以及问题开始的地方。数据在控制台中完美显示 - 每个对象及其属性都详细说明:
http://i.imgur.com/LiVRgjw.png
因此,数据已正确接收,并且API本身没有问题。当我看到的所有内容都是[object Object]时,问题出现在网站上:
http://i.imgur.com/Q5jYwp2.png
我试图将Book包装在div中,并且还只是一个带有book.title的div,以查看问题是否与组件呈现有关,但我得到了相同的东西。 只有当我将输出设置为普通的book.title时,没有div或花括号我会逐个获得标题。
.then(data => {
let output = ''
for (let book of data) {
output += (
book.title
);
}
所以我的问题:我如何使这项工作?如何在GET请求中实现我的Book组件,以便为数据库中的每个对象呈现可重用的Book?
我在网上搜索了几天,却找不到答案。 我认为这是一个非常基本的障碍,我不是唯一一个面对它的人。 非常感谢你的帮助,期待阅读你的建议!
编辑#1 根据我到目前为止所学到的,需要将来自GET请求的数据存储在容器组件的状态中,并将其作为props传递给表示组件。在我的例子中,它在LibraryProject组件内的componentDidMount()中调用请求,并将其作为props传递给负责显示信息的Book组件。
//LibraryProject.js
componentDidMount () {
fetch('http://localhost:8000/api/Books')
.then(response => {
if (!response.ok) {
throw Error('Network request failed.')
}
return response;
})
.then(data => data.json())
.then(data => {
this.setState({
content: data
});
console.log('parsed json', data);
}, (ex) => {
this.setState({
requestError : true
});
console.log('parsing failed', ex)
})
}
render () {
return (
<div>
...
<div className="book-filter">
<button id="search-books"
onClick={this.handleSearch.bind(this)}>
Search for books
</button>
...
<div id="database">
{this.state.database ? <Book list={this.state.content} /> : <h4>Books will be shown here...</h4>}
{this.state.requestError ? <h4>Failed to get the data. Please check the log for errors.</h4> : ''}
</div>
</div>
)
}
//Book.js
class Book extends React.Component{
constructor (props){
super(props);
this.state = {
list : this.props.list
}
}
render() {
let list = this.state.list;
for (let book of list){
return(
<li key={book._id}>
<p><span className="noedit title">{book.title}</span>
...
</li>
)
}
}
}
问题现在是我只得到一个从'list'渲染的项目,它是一个对象数组 - [{},{},{}]。 知道为什么吗?
编辑#2 - 最终 好的,所以我设法让它全部工作。 显然,根据React文档:“如果语句和for循环不是JavaScript中的表达式,那么它们就不能直接在JSX中使用”。 所以这是有效的:
//Book.js
class Book extends React.Component{
constructor (props){
super(props);
this.state = {
edit : false,
list : this.props.list
}
}
componentWillReceiveProps(nextProps) { //for Updating
if (nextProps.list !== this.state.list) {
this.setState({ list: nextProps.list });
}
}
render() {
return(
<div>
{this.state.list.map((book) =>
<li key={book._id}>
<p><span className="noedit title">{book.title}</span>
...
</li>
)}
</div>)
}
}
我所做的是使用.map作为我的渲染函数中的表达式并将其包装在div中。 希望这对任何人都有帮助,谢谢@Ha Ja的帮助。
答案 0 :(得分:2)
您应该将api的结果存储在状态中,并在<Book />
函数内呈现render
。
顺便说一句,分开你的组件会更好:
您甚至可以使用redux
来处理全局状态,redux-saga
来处理副作用(api调用)
修改强>
这是一个小例子。
演示组成部分:
const BookListing = ({ books }) => (
<ul>
{books.map(book => <li key={book.id}>{book.title}</li>)}
</ul>
);
容器组件:
class Books extends Component {
constructor(props) {
super(props);
this.state = {books: []};
}
componentDidMount() {
fetch('http://localhost:8000/api/Books')
.then(data => data.json())
.then((data) => { this.setState({ books: data }) });
}
render() {
return <BookListing books={this.state.books} />;
}
}
答案 1 :(得分:0)
1)创建一个容器组件,您可以在其中执行AJAX请求,然后将结果保存在本地状态,例如books
方法中的render
。
2)将this.state.books
传递到您可以迭代阵列的<Book />
组件中。
3)(可选但推荐)。您可以创建另一个组件,如<BookDetail />
,以呈现单个图书项目