I'm new to Typescript and I have to get a list of books from an API. My profesor gave me the code in javascript to do this, but I have to do this in typescript and react native.
Getting api:
import axios from 'axios';
const api = axios.create({
baseURL: "https://hn.algolia.com/api/v1"
});
export default api;
List component:
import React, { Component } from "react";
import './List.css';
class List extends Component {
constructor(props: any) {
super(props);
this.state = {};
}
render() {
const apiData = this.props;
return (
<div className="List">
{apiData?.map(item => (
<div className="Livro">
<h3> {item.name}</h3>
<p> {item.authors.join(',')}</p>
<p><a href={item.url} target='_blank' rel="noreferrer"> {item.url}</a></p>
</div>
))}
</div>
);
}
}
export default List;
An example how I will call the List component:
import React, {Component} from 'react';
import List from '../../components/list'
import api from '../../_config/api';
import './Welcome.css';
class Welcome extends Component {
constructor(props){
super(props);
this.state = {sectionData:props.sectionData}
this.filterList = this.filterList.bind(this);
this.fetchData = this.fetchData.bind(this);
}
async fetchData(value) {
const response = await api.get('/books?name=' value)
this.setState({sectionData:response?.data})
}
async componentDidMount(){
this.fetchData('');
}
render() {
const {sectionData} = this.state;
return (
<div className="Welcome">
<List data={sectionData}/>
</div>
);
}
}
export default Welcome;
The part of the code that only works in Javascript:
return (
<div className="List">
{apiData?.map(item => ( // error here
<div className="Livro">
<h3> {item.name}</h3>
<p> {item.authors.join(',')}</p>
<p><a href={item.url} target='_blank' rel="noreferrer"> {item.url}</a></p>
</div>
))}
</div>
);
I tried to do this the same way in typescript, but it return this error:
Type error: Property 'map' does not exist on type 'Readonly<{}> & Readonly<{ children?: ReactNode; }>'.
Is there any way to resolve this error or another way to map an API without using map()?
CodePudding user response:
Try creating an interface for your List
component, and put the interface on your component like below.
interface IListProps {
apiData?: { name: string, authors: string[] }[];
}
interface IListState {}
class List extends Component<IListProps, IListState> {
// your code...
}
I also see that your props
on the List
component inside the render
of the Welcome
component are wrong.
interface IWelcomeProps {
sectionData?: { name: string, authors: string[] }[];
}
interface IWelcomeState extends IWelcomeProps {} // extends the props from IWelcomeProps
class Welcome extends Component<IWelcomeProps, IWelcomeState> {
// your code...
render() {
const { sectionData } = this.state;
return (
<div className="Welcome">
<List apiData={sectionData}/> // replace data by apiData
</div>
);
}
}
You can find more info about how to use interfaces here.
CodePudding user response:
Starting from xZliman idea, I researched and get no error when doind this:
class List extends Component {
constructor(props: any) {
super(props);
this.state = {};
}
render() {
const apiData = this.props as {name: string, authors: string[], url: string}[]; // Here is the change
return (
<div className="List">
{apiData.map(item => (
<div className="Livro">
<h3> {item.name}</h3>
<p> {item.authors.join(',')}</p>
<p><a href={item.url} target='_blank' rel="noreferrer"> {item.url}</a></p>
</div>
))}
</div>
);
}
}
export default List;
Maybe it isn't a good solution, but it gets the work done as a workaround.