javascript - Fetch GET request with Reactjs - how do i implement a reusable component within my request to render my data? -
i have been practicing apis while, created own books api practice with. have made full functional library ajax requests working properly, using html , javascript-es6. moved on study reactjs , tried build same library using react. when comes dealing api heard fetch choice. request using fetch:
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 = '' (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) })
as can see, book component right there getting information props , child component of parent "libraryproject" component. book looks that:
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> ) }}
it expected have edit , remove functions, hence structure.
now, call being made when user clicks button, no use of componentdidmount or other lifecycle, request implemented within handleclick function.
as can see, console.log data within request. , thats problem begins. data shown in console - every object , properties detailed:
http://i.imgur.com/livrgjw.png
so data recieved properly, , no problem api itself. problem in website when see [object object] this:
http://i.imgur.com/q5jywp2.png
i have tried wrap book inside div, , div book.title example, see if problem component rendering, same thing. when set output plain book.title, no divs or curly braces titles 1 after another.
.then(data => { let output = '' (let book of data) { output += ( book.title ); }
so question: how make work? how implement book component inside request render reusable book every object in database?
i have searched web few days , couldn't find answer. believe basic obstacle , not 1 faced it. thank help, looking forward reading advice!
edit #1 i've learned far required store data request in container component's state , pass down presentational component props. in case calling request in componentdidmount() inside libraryproject component, , pass props book component responsible on presenting information.
//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 books </button> ... <div id="database"> {this.state.database ? <book list={this.state.content} /> : <h4>books shown here...</h4>} {this.state.requesterror ? <h4>failed data. please check log 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; (let book of list){ return( <li key={book._id}> <p><span classname="noedit title">{book.title}</span> ... </li> ) } } }
the problem 1 item rendered 'list' array of objects - [ {},{},{} ]. idea why?
edit #2 - final ok managed make work. apparently, according react docs: "if statements , loops not expressions in javascript, can't used in jsx directly". here's works:
//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>) } }
what did using .map expression inside render function , wrapped in div. hope helps anyone, thank @ha ja help.
you should store result of api inside state , render <book />
inside render
function.
btw better separate components:
- the container logic (data fetching, ...).
- the presentational component renders ui.
you can go further using redux
handling global state, , redux-saga
handling side effects (api calls)
edit
here small example.
the presentational component:
const booklisting = ({ books }) => ( <ul> {books.map(book => <li key={book.id}>{book.title}</li>)} </ul> );
the container component:
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} />; } }
Comments
Post a Comment