I'm new in REACT with typescript and I'm meeting some problems.
I have a page (FanClub.tsx) that getting data from web and display many components (FanComponent.txs). There are the good number of components, but I'm passing values to components and there is no displaying of this values.
I made a repo on github to test if you want to try/test: github react problem
If anyone can tell me why the props (parameters in component) are not displaying.
Thanks.
FanClub.tsx
import React, { useState, useEffect } from 'react';
import { useQuery } from "react-query";
import FanComponent from '../components/FanComponent';
import Navbar from '../components/Navbar/Navbar';
import '../css/fanapp.css';
import Fan from '../Models/Fan';
import AccessDataService from '../Services/AccessDataService';
const FanClub: React.FC = () => {
const [allFans, setAllFans] = useState<Fan[]>([]);
useEffect(() => {
console.log("Je suis dans useEffect, et allFans contient :")
console.log(allFans.length + " éléments");
}, [allFans]);
useQuery<Fan[]>(
"query-fans",
async () => {
console.log("Coucou, je suis ici : query-fans !");
// Oui, je sais, mais rien ne vaut un "coucou je suis ici"
return await AccessDataService.GetAllFans();
},
{
enabled: true,
onSuccess: (res) => {
setAllFans(res);
},
onError: (err: any) => {
console.error("ERREUR 12 - " + err);
setAllFans([]);
},
}
);
return (
<div className="page">
<div className="sidebar">
<Navbar />
</div>
<div className='row'>
<div>Coucou de la FanClub page</div>
<div className="fanClub">
{allFans.map((fan) =>
(
<FanComponent key={fan.Id}
nom={fan.Nom}
id={fan.Id}
nombreClick={fan.NombreDeClickRecu} />
))
}
</div>
</div>
</div>
);
}
export default FanClub;
And FanComponent.tsx
import { Component } from 'react';
import './FanComponent.css';
interface FanComponentProps {
id: number;
nom: string;
nombreClick: number;
}
export default class FanComponent extends Component<FanComponentProps> {
constructor(props: FanComponentProps)
{
super(props);
}
render() {
const { id, nom, nombreClick } = this.props;
return (
<div className="fan grow">
<div>
<div>ID : {id}</div>
<div>Nom : {nom}</div>
<div>Nombre de click : {nombreClick}</div>
</div>
<button>
Click sur Moi
</button>
</div>
);
}
}
I found the problem.
My interface Fan does not represent the name of JSON properties.
The JSON data :
[
{
"id": 1,
"nom": "Michel",
"nombreDeClickRecu": 0,
"infoDiverses": "Plein d'infos",
"dateInscription": "2018-05-10T00:00:00"
},
{
"id": 2,
"nom": "Jean",
"nombreDeClickRecu": 0,
"infoDiverses": "Plein d'infos",
"dateInscription": "2018-05-10T00:00:00"
}
]
Before :
export default interface Fan
{
Id: number,
Nom: string,
NombreDeClickRecu: number,
InfoDiverses: string,
DateInscription: Date,
}
After :
export default interface Fan
{
id: number,
nom: string,
nombreDeClickRecu: number,
infoDiverses: string,
dateInscription: Date,
}
Related
I'm using Sanity in a project and came across an error when I tried to pass props to a component
that says: "Type 'Card[]' is missing the following properties from type 'Card': _type, title, image, description, and 4 more." Card in this context is one of my schemas for Sanity that I created. When I run my web app, I also get: "SyntaxError: Unexpected token < in JSON at position 0" I'm trying to figure out why my fetching data won't work.
I've checked my type definition file, my fetch functions etc to make sure that everything connected correctly and and I didn't have any spelling or importing errors. I've also tried restarting my server. At the bottom of my index page, i'm using a getStaticProps async function. When I comment it out, my app runs, so the problem has something to do with that.
my code:
Index:
import type { GetStaticProps} from 'next';
import Head from 'next/head'
import Image from 'next/image'
import React from 'react'
import Header from 'components/Header'
import Hero from 'components/Hero'
import Middle from 'components/Middle'
import Chapters from 'components/Chapters'
import Footer from 'components/Footer'
import {Card, CardList, Chapter, Banner, Pages, Summary, SlideCard} from "typings"
import { fetchCard} from 'utils/fetchCard'
import { fetchCardList} from 'utils/fetchCardList'
import {fetchChapter} from 'utils/fetchChapter'
import {fetchBanner} from 'utils/fetchBanner'
import { fetchPages} from 'utils/fetchPages'
import { fetchSummary} from 'utils/fetchSummary'
import { fetchSlideCard} from 'utils/fetchSlideCard'
type Props = {
card: Card[];
cardList: CardList[];
chapter: Chapter[];
banner: Banner[];
pages: Pages[];
summary: Summary[];
slideCard: SlideCard[];
}
export default function Home({card, cardList, chapter, banner, pages, summary, slideCard}: Props ) {
return (
<>
<Head>
<title>Shonen Jump Plus 2</title>
<link rel="icon" href="/favicon.ico" />
</Head>
<main className="max-w-screen-2xl mx-auto">
<div>
<Header />
<Hero card={card}/>
<Middle />
<Chapters />
<Footer />
{/* Hero Slides */}
{/* Four Featured */}
{/* Latest Chapters */}
</div>
</main>
</>
)
}
export const getStaticProps: GetStaticProps<Props> = async () => {
const card: Card[] = await fetchCard();
const cardList: CardList[] = await fetchCardList();
const chapter: Chapter[] = await fetchChapter();
const banner: Banner[] = await fetchBanner();
const pages: Pages[] = await fetchPages();
const slideCard: SlideCard[] = await fetchSlideCard();
const summary: Summary[] = await fetchSummary();
return {
props: {
card,
cardList,
chapter,
banner,
pages,
slideCard,
summary,
},
revalidate: 2,
};
};
Type Definitions:
interface SanityBody {
_createdAt: string;
_id: string;
_rev: string;
_updatedAt: string;
}
export interface Image extends SanityBody {
_type:"image";
asset: {
_ref: string;
_type: "reference"
};
}
export interface Card extends SanityBody {
_type: "card";
title: string;
image: Image;
description:Text;
}
export interface Banner extends SanityBody {
_type: "banner";
title: string;
image: Image;
}
export interface Pages extends SanityBody {
_type: "pages"
page1: Image;
}
export interface CardList extends SanityBody {
_type: "cardList"
thumbnail:Image;
title:string;
author:string;
chapter:string;
subtitle:string;
date:string;
}
export interface SlideCard extends SanityBody {
_type: "slideCard"
image:Image;
title:string;
chapter:string;
}
export interface Summary extends SanityBody {
_type: "summary"
title:string;
author:string;
description:Text;
}
export interface Chapter extends SanityBody {
_type: "chapter"
title:string;
date:string;
}
card schema:
export default {
name: 'card',
title: 'Card',
type: 'document',
fields: [
{
name: 'thumbnail',
title: 'Thumbnail',
type: 'image',
},
{
name: 'title',
title: 'Title',
type: 'string',
},
{
name: 'description',
title: 'Description',
type: 'text',
},
],
}
getCard:
fetching data on the front-end
//Next.js API route support: https://nextjs.org/docs/api-routes/introduction
import type {NextApiRequest, NextApiResponse} from "next";
import {groq} from "next-sanity";
import {sanityClient} from "sanity";
import { Card } from "typings";
const query = groq`
*[_type == "card"]
`
type Data = {
card: Card[];
}
export default async function handler(
req: NextApiRequest,
res: NextApiResponse<Data>
) {
const card: Card[] = await sanityClient.fetch(query);
res.status(200).json({ card })
}
fetchCard:
fetching data on the back-end
import {Card} from "typings";
export const fetchCard = async() => {
const res = await fetch (`${process.env.NEXT_PUBLIC_BASE_URL}/api/getCard`);
const data = await res.json();
const card: Card[] = data.card;
return card;
};
I'm implementing a Like and Dislike Button, and I wanna that when I click them will be with other colors, but just the clicked component, when I click all buttons change the state, can anybody help me?
`
const indexPost = async () => {
const data = await api.get('/api/posts')
if(data.data.length !=0){
const dataArray = data.data
if(dataArray.length === 0) {
return
}else{
return(
setPost(dataArray.map( data => (
<Post key={data._id} id={data._id} title={data.title} text={data.text}>
<Like id={data._id}></Like>
</Post>
)))
)
}
}
}
export default function Like({itemId}) {
const context = useContext(notificationContext)
const {isLoved, Like, Loved, Unlike, isLike, isUnlike, setIsLike, setIsUnlike, setIsLoved } = context
return(
<div className={styles.likeContainer} key={itemId}>
{isLike ? (
<button className={styles.likeContent} onClick={() => setIsLike(false)}><Icon.ThumbsUp className={styles.Icon} fill="#5CB0BB" ></Icon.ThumbsUp></button>) :
(<button className={styles.likeContent} onClick={() => Like() }><Icon.ThumbsUp className={styles.Icon} ></Icon.ThumbsUp></button>)}
{isLoved ?
(<button className={styles.likeContent} onClick={() => setIsLoved(false)}><Icon.Heart className={styles.Icon} fill="red" ></Icon.Heart> </button>) :
(<button className={styles.likeContent} onClick={() => Loved() }><Icon.Heart className={styles.Icon} ></Icon.Heart></button>)}
{isUnlike ? (
<button className={styles.likeContent} onClick={() => setIsUnlike(false)}><Icon.ThumbsDown className={styles.Icon} fill="#702BA6" ></Icon.ThumbsDown> </button>) :
(<button className={styles.likeContent} onClick={() => Unlike()}><Icon.ThumbsDown className={styles.Icon} ></Icon.ThumbsDown></button>
)}
</div>
)
};
I have implemented the similar one in my project, it is very basic , it shows how to update the likes , you need to handle the cases of user authentication and stuff
App.js
import { useState, useEffect, createContext, useReducer } from "react";
import { updateArrayOfObj } from "./utils";
import AllPosts from "./AllPosts";
export const PostsContext = createContext();
const initialState = {
posts: [
{
_id: "1",
name: "Browny",
image: "http://placekitten.com/200/310",
likes: 0,
love: 0,
dislikes: 0
},
{
_id: "2",
name: "Blacky",
image: "http://placekitten.com/200/320",
likes: 0,
love: 0,
dislikes: 0
},
{
_id: "3",
name: "SnowWhite",
image: "http://placekitten.com/200/300",
likes: 0,
love: 0,
dislikes: 0
}
]
};
const reducer = (state, action) => {
switch (action.type) {
case "UPDATE_POST":
return {
...state,
posts: updateArrayOfObj(
state.posts,
action.payload.obj,
"_id",
action.payload._id
)
};
case "CREATE_POST":
return {
...state,
posts: [...state.posts, ...action.payload.data]
};
case "DELETE_POST":
return {
...state,
posts: state.posts.filter((ele) => ele._id !== action.payload._id)
};
default:
return state;
}
};
export default function App() {
const [state, dispatch] = useReducer(reducer, initialState);
return (
<PostsContext.Provider
value={{
state,
dispatch
}}
>
<div className="App">
<AllPosts />
</div>
</PostsContext.Provider>
);
}
PostsAll.js
import Post from "./Post";
import { PostsContext } from "./App";
import { useContext } from "react";
export default function AllPosts() {
const { state } = useContext(PostsContext);
return (
<div className="allPosts">
{state.posts.map((item) => {
return (
<Post
name={item.name}
image={item.image}
likes={item.likes}
love={item.love}
dislikes={item.dislikes}
id={item._id}
key={item._id}
/>
);
})}
</div>
);
}
Post.js
import { PostsContext } from "./App";
import { useContext } from "react";
export default function Post(props) {
const { state, dispatch } = useContext(PostsContext);
const handleUserInteraction = (type, id) => {
dispatch({
type: "UPDATE_POST",
payload: {
obj: { [type]: props[type] + 1 },
_id: id
}
});
};
return (
<div className="post">
<h3>{props.name}</h3>
<img src={props.image} alt="cat" />
<br />
<button onClick={() => handleUserInteraction("likes", props.id)}>
{props.likes} Like
</button>{" "}
<button onClick={() => handleUserInteraction("love", props.id)}>
{props.love} Love
</button>{" "}
<button onClick={() => handleUserInteraction("dislikes", props.id)}>
{props.dislikes} Dislike
</button>
</div>
);
}
You can refer to this codesandbox to implement the same
You can use onClick() on each like button and attach it with a function, then you can get the value of that particular like with e.currentTarget.id and change its css/style the way you want.
const handleClick=(e)=>
{
console.log(e.currentTarget.id);
}
I want to implement a search bar in my reactJS which takes query in the search bar and show the matching assets from the API with that query till it is finished and rendering it.
import React, { Component } from 'react';
interface ApiResponse {
data: Asset[];
}
interface FetchDataExampleState
{
query: string;
assets: Asset[];
}
// The interface for our Language model.
interface Asset
{
city: string;
country: string;
lane_number: string;
location_uuid: string;
pin: string;
id: BigInt;
}
class Search extends Component<{}, FetchDataExampleState> {
constructor(props) {
super(props)
this.state = {
query: '',
assets: []
}
}
componentDidMount() {
this.serachPeople(this.state.query);
}
onChange(e) {
this.setState({ query: e.target.value }, () => {
if (this.state.query && this.state.query.length > 1) {
if (this.state.query.length % 2 === 0) {
this.serachPeople(this.state.query);
}
} else {
this.serachPeople(this.state.query);
}
})
}
serachPeople(query) {
const url = "/api/locations";
if (query) {
fetch(url, {
method: 'GET'
})
.then(response => response.json() as Promise<ApiResponse>)
.then(data => {
console.log(data.data)
// This is showing 0: {city: "bangalore", country: "india", id: 1, lane_number: "10", location_uuid: "1158", …}
//I have to search for location_uuid and show the row
}
}
render() {
return (
<form>
<input
type="text"
className="search-box"
placeholder="Search for..."
onChange={this.onChange.bind(this)}
/>
{this.state.assets}
</form>
)
}
}
export default Search;
How to render all the matching location_uuids till the last one.
Then render the keys and values of the last one. I am new to ReactJS and tried other solutions. Can anybody help me with this?
I'm currently trying to take some JSON data that I've received from an API and put that into a dropdown in a very simple React application.
This is my DropDown component thus far:
import React from 'react';
var values;
fetch('http://localhost:8080/values')
.then(function(res) {
return res.json();
}).then(function(json) {
values = json;
console.log(values);
});
class DropDown extends React.Component {
render(){
return <div className="drop-down">
<p>I would like to render a dropdown here from the values object</p>
</div>;
}
}
export default DropDown;
Any my JSON looks like this:
{
"values":[
{
"id":0,
"name":"Jeff"
},
{
"id":1,
"name":"Joe"
},
{
"id":2,
"name":"John"
},
{
"id":3,
"name":"Billy"
},
{
"id":4,
"name":"Horace"
},
{
"id":5,
"name":"Greg"
}
]
}
I'd like the dropdown options to correspond to the 'name' of each element, and the 'id' to be used as an element identifier when an event is triggered by selecting an option. Any advice on getting this data into a dropdown which responds to user input would be greatly appreciated.
Call the API in componentDidMount lifecycle function of your React component and then save the response in state and then render the Select dropdown
import React from 'react';
class DropDown extends React.Component {
state = {
values: []
}
componentDidMount() {
fetch('http://localhost:8080/values')
.then(function(res) {
return res.json();
}).then((json)=> {
this.setState({
values: json
})
});
}
render(){
return <div className="drop-down">
<p>I would like to render a dropdown here from the values object</p>
<select>{
this.state.values.map((obj) => {
return <option value={obj.id}>{obj.name}</option>
})
}</select>
</div>;
}
}
export default DropDown;
You could do something like this:
import React from 'react';
var values;
class DropDown extends React.Component {
constructor(){
super();
this.state = {
options: []
}
}
componentDidMount(){
this.fetchOptions()
}
fetchOptions(){
fetch('http://localhost:8080/values')
.then((res) => {
return res.json();
}).then((json) => {
values = json;
this.setState({options: values.values})
console.log(values);
});
}
render(){
return <div className="drop-down">
<select>
{ this.state.options.map((option, key) => <option key={key} >{option}</option>) }
</select>
</div>;
}
}
export default DropDown;
Basically you are initializing state and setting options to null.
You are then fetching your options when the component mounts in the browser. These values are set to your state with this.setState().
Note: It is important to make any API calls in componentDidMount() and not componentWillMount(). If you call it in componentWillMount() the request will be made twice.
Then you render these options by mapping them in your render function
JSON FILE: terrifcalculatordata.json
[
{
"id": 1,
"name": "Vigo",
},
{
"id": 2,
"name": "Mercedes",
},
{
"id": 3,
"name": "Lexus",
},
{
"id": 4,
"name": "Buggati",
},
]
CODE:
1st import json file on top:
import calculatorData from "../static/data/terrifcalculatordata.json";
2nd in render method type this code:
<Form>
<FormGroup>
<Input
type="select"
onChange = {this.changeCarmodel}
value={this.state.changeCar}
>
{calculatorData.map((caldata, index) =>
<option
key={index}
value= {caldata.id}
> {caldata.name} </option>
)}
</Input>
</FormGroup>
</Form>
How to render JSON response as dropdown list in React.
export default class ExpenseNew extends Component {
constructor(){
super();
this.state={
PickerSelectedVal : '',
accountnameMain:[],
}
}
componentDidMount(){
var account_nam=[]
fetch('your Url', {
method: 'GET',
headers: { 'Authorization': 'Bearer ' + your token }
})
.then((response) => response.json())
.then((customerselect) => {
// alert(JSON.stringify(customerselect))
global.customerdata = JSON.stringify(customerselect)
var customername = JSON.parse(customerdata);
//alert(JSON.stringify(customername));
for (i = 0; i < customername.cus_data.length; i++) {
var dataa = customername.cus_data[i]["account_name"];
account_nam.push(dataa)
}
this.setState({accountnameMain:account_nam});
})
.done();
}
render() {
return (
<Picker
selectedValue={this.state.PickerSelectedVal}
placeholder="Select your customer"
mode="dropdown"
iosIcon={<Icon name="arrow-down" />}
onValueChange={(itemValue, itemIndex) => this.setState({PickerSelectedVal: itemValue})} >
{this.state.accountnameMain.map((item, key)=>(
<Picker.Item label={item} value={item} key={key}/>)
)}
</Picker>
)
}
}
could you please tell me how to render a list in react js.
I do like this
https://plnkr.co/edit/X9Ov5roJtTSk9YhqYUdp?p=preview
class First extends React.Component {
constructor (props){
super(props);
}
render() {
const data =[{"name":"test1"},{"name":"test2"}];
const listItems = data.map((d) => <li key={d.name}>{d.name}</li>;
return (
<div>
hello
</div>
);
}
}
You can do it in two ways:
First:
render() {
const data =[{"name":"test1"},{"name":"test2"}];
const listItems = data.map((d) => <li key={d.name}>{d.name}</li>);
return (
<div>
{listItems }
</div>
);
}
Second: Directly write the map function in the return
render() {
const data =[{"name":"test1"},{"name":"test2"}];
return (
<div>
{data.map(function(d, idx){
return (<li key={idx}>{d.name}</li>)
})}
</div>
);
}
https://facebook.github.io/react/docs/jsx-in-depth.html#javascript-expressions
You can pass any JavaScript expression as children, by enclosing it within {}. For example, these expressions are equivalent:
<MyComponent>foo</MyComponent>
<MyComponent>{'foo'}</MyComponent>
This is often useful for rendering a list of JSX expressions of arbitrary length. For example, this renders an HTML list:
function Item(props) {
return <li>{props.message}</li>;
}
function TodoList() {
const todos = ['finish doc', 'submit pr', 'nag dan to review'];
return (
<ul>
{todos.map((message) => <Item key={message} message={message} />)}
</ul>
);
}
class First extends React.Component {
constructor(props) {
super(props);
this.state = {
data: [{name: 'bob'}, {name: 'chris'}],
};
}
render() {
return (
<ul>
{this.state.data.map(d => <li key={d.name}>{d.name}</li>)}
</ul>
);
}
}
ReactDOM.render(
<First />,
document.getElementById('root')
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="root"></div>
Shubham's answer explains very well. This answer is addition to it as per to avoid some pitfalls and refactoring to a more readable syntax
Pitfall : There is common misconception in rendering array of objects especially if there is an update or delete action performed on data. Use case would be like deleting an item from table row. Sometimes when row which is expected to be deleted, does not get deleted and instead other row gets deleted.
To avoid this, use key prop in root element which is looped over in JSX tree of .map(). Also adding React's Fragment will avoid adding another element in between of ul and li when rendered via calling method.
state = {
userData: [
{ id: '1', name: 'Joe', user_type: 'Developer' },
{ id: '2', name: 'Hill', user_type: 'Designer' }
]
};
deleteUser = id => {
// delete operation to remove item
};
renderItems = () => {
const data = this.state.userData;
const mapRows = data.map((item, index) => (
<Fragment key={item.id}>
<li>
{/* Passing unique value to 'key' prop, eases process for virtual DOM to remove specific element and update HTML tree */}
<span>Name : {item.name}</span>
<span>User Type: {item.user_type}</span>
<button onClick={() => this.deleteUser(item.id)}>
Delete User
</button>
</li>
</Fragment>
));
return mapRows;
};
render() {
return <ul>{this.renderItems()}</ul>;
}
Important : Decision to use which value should we pass to key prop also matters as common way is to use index parameter provided by .map().
TLDR; But there's a drawback to it and avoid it as much as possible and use any unique id from data which is being iterated such as item.id. There's a good article on this - https://medium.com/#robinpokorny/index-as-a-key-is-an-anti-pattern-e0349aece318
Try this below code in app.js file, easy to understand
function List({}) {
var nameList = [
{ id: "01", firstname: "Rahul", lastname: "Gulati" },
{ id: "02", firstname: "Ronak", lastname: "Gupta" },
{ id: "03", firstname: "Vaishali", lastname: "Kohli" },
{ id: "04", firstname: "Peter", lastname: "Sharma" }
];
const itemList = nameList.map((item) => (
<li>
{item.firstname} {item.lastname}
</li>
));
return (
<div>
<ol style={{ listStyleType: "none" }}>{itemList}</ol>
</div>
);
}
export default function App() {
return (
<div className="App">
<List />
</div>
);
}
import React from 'react';
class RentalHome extends React.Component{
constructor(){
super();
this.state = {
rentals:[{
_id: 1,
title: "Nice Shahghouse Biryani",
city: "Hyderabad",
category: "condo",
image: "http://via.placeholder.com/350x250",
numOfRooms: 4,
shared: true,
description: "Very nice apartment in center of the city.",
dailyPrice: 43
},
{
_id: 2,
title: "Modern apartment in center",
city: "Bangalore",
category: "apartment",
image: "http://via.placeholder.com/350x250",
numOfRooms: 1,
shared: false,
description: "Very nice apartment in center of the city.",
dailyPrice: 11
},
{
_id: 3,
title: "Old house in nature",
city: "Patna",
category: "house",
image: "http://via.placeholder.com/350x250",
numOfRooms: 5,
shared: true,
description: "Very nice apartment in center of the city.",
dailyPrice: 23
}]
}
}
render(){
const {rentals} = this.state;
return(
<div className="card-list">
<div className="container">
<h1 className="page-title">Your Home All Around the World</h1>
<div className="row">
{
rentals.map((rental)=>{
return(
<div key={rental._id} className="col-md-3">
<div className="card bwm-card">
<img
className="card-img-top"
src={rental.image}
alt={rental.title} />
<div className="card-body">
<h6 className="card-subtitle mb-0 text-muted">
{rental.shared} {rental.category} {rental.city}
</h6>
<h5 className="card-title big-font">
{rental.title}
</h5>
<p className="card-text">
${rental.dailyPrice} per Night · Free Cancelation
</p>
</div>
</div>
</div>
)
})
}
</div>
</div>
</div>
)
}
}
export default RentalHome;
Try this:
class First extends React.Component {
constructor (props){
super(props);
}
render() {
const data =[{"name":"test1"},{"name":"test2"}];
const listItems = data.map((d) => <li key={d.name}>{d.name}</li>;
return (
<div>
{listItems}
</div>
);
}
}