Im trying to filter data with multiple key value in reactjs with tsx. Cards.tsx is a parent component and ShipmentCard.tsx is a child. I'm getting Property 'toLowerCase' does not exist on type 'never'
error. I just want to return the related object based on search criteria. Can anyone let me know where I made a mistake?
Cards.tsx
class Cards extends Component { state = { card: [], filter: "" }; componentDidMount() { this.loadShipmentList(); } handleChange = (event: any) => { this.setState({ filter: event.target.value }); }; loadShipmentList() { fetch("http://localhost:3001/shipments") .then(response => response.json()) .then(data => this.setState({ card: data })); } render() { const { card, filter } = this.state; const lowercasedFilter = filter.toLowerCase(); const filteredData = this.state.card.filter(item => { return Object.keys(item).some(key => item[key].toLowerCase().includes(lowercasedFilter) ); }); return ( <Card className="Search-Bar"> <CardContent> <Grid container spacing={3}> <TextField label="Search" onChange={this.handleChange} /> </Grid> </CardContent> </Card> <Grid container spacing={3}> {filteredData.map((card: any) => ( <Grid item xs={12}> <ShipmentCard key={card.id} value={card} /> </Grid> ))} </Grid> ); } } export default Cards;
{ "shipments": [ { "id": "123", "name": "Heromisha", "total": "1000", "status": "ACTIVE", "userId": "E222" }, { "id": "456", "name": "Honda", "total": "3000", "status": "ACTIVE", "userId": "E111" } ] }
Component
is a generic interface with two type parameters: The type of your props, and the type of your state. Your component doesn't seem to have props so you can just use object
or {}
for the props interface, but you do have state, so you need to say what shape that state has:
interface Card {
id: string;
name: string;
total: string;
status: string;
userId: string;
}
interface CardsState {
card: Card[];
filter: string;
}
class Cards extends Component<object,CardsState> {
state: CardsState = {
card: [],
filter: ""
};
// ...
}
Separately, the next couple of problems I suspect you'll have are:
You're not checking that fetch
succeeded. You're not alone in this, it's a very common error (so common I wrote it up on my anemic little blog). You need to add a check to your fetch
call:
fetch("http://localhost:3001/shipments") .then(response => { if (!response.ok) { throw new Error("HTTP error " + response.status); } return response.json(); }) // ...
You're not handling errors from fetch
. loadShipmentList
should either return the promise chain (and then componentDidMount
and other places it's used would handle errors) or handle/report errors itself.
You're setting card
to the result of parsing your JSON. Your code assumes card
is an array, but the JSON's top level isn't an array, it's an object with a shipments
property (which is an array). I suspect you meant to set card
(which should be cards
, plural, or shipments
) to the shipments
property of the returned data:
.then(({shipments}) => this.setState({ card: shipments })); // ^^ ^^ ^^^^^^^^^
There may be further issues, but the main answer above should address the never
issue, and hopefully these further hints have helped.
In a comment you've said that when you give card
a type, this code causes an error:
const filteredData = this.state.card.filter(item => {
return Object.keys(item).some(key =>
item[key].toLowerCase().includes(lowercasedFilter)
);
});
If you expect the shape of the data in the JSON to be variable, you could declare card
as any[]
(or perhaps Record<string,string>[]
) and then that dynamic code would work. But only if you want the component driven by the JSON. Otherwise, update the code to use the typesafe property names:
const filteredData = this.state.card.filter(({id, name, total, status, userId}) =>
`${id}\t${name}\t${total}\t${status}\t${userId}`.toLowerCase().includes(lowercasedFilter)
);
The compiler doesn't real type of state.card[...], becouse it's declared as array. The most simple way is to declare this as any[]
state = {
card: [] as any[],
filter: ""
};
Or describe data type explicit
interface Card {
"id": string,
"name": string,
"total": string,
"status": string,
"userId": string
}
...
state = {
card: [] as Card[],
filter: ""
};
Or by object example
const cardSample = {
"id": "123",
"name": "Heromisha",
"total": "1000",
"status": "ACTIVE",
"userId": "E222"
};
type Card = typeof cardSample;
...
state = {
card: [] as Card[],
filter: ""
};
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.