I am trying to render static images from images folder under src directory, however, it is not rendering, if i try to import any of the images directly and then pass in jsx like commented portion in images declaration it renders fine, also tried with backgroundImage property of css, it does not render anything.
import React, { Component } from 'react';
import Pizza from './components/pizza';
import './App.css';
class App extends Component {
state = {
open: false,
active: null,
categories: []
}
componentDidMount() {
this.setState({
categories
})
}
render() {
return (
<div className="App">
<Pizza data={this.state}/>
</div>
);
}
}
const categories = [
{"title":"Italian Pizza","link":"../images/italian-pizza.jpg",
"id":"586537da62981d5fb8c21617",
"details": "aksnflafiafoasofhafhoahfohaofhoahfhashfohasfhofhahsofohahosf"}
];
export default App;
pizza.js
import React from 'react';
import PropTypes from 'prop-types';
import italian from '../images/italian-pizza.jpg'
const Pizza = ({data}) => {
const images = data.categories.map((d,i) => {
return (
<div key={i}>
{/* <img src={italian} /> */}
<img src={`${d.link}`} />
</div>
)
});
return (
<div className="pizza">
<header className="header">Pizza</header>
<div className="main">
{data.categories.map((category, index) => {
return (
<div key={index}>
<ul className="items">
{images}
{/* <li style={{backgroundImage: `url(require(italian))`}} /> */}
</ul>
</div>
)
})}
</div>
</div>
)
}
Pizza.propTypes = {
categories: PropTypes.array,
open: PropTypes.bool,
active: PropTypes.bool
}
export default Pizza;
Related
Error: Type '{ children: Element; }' has no properties in common with
type 'IntrinsicAttributes & Pick<ClassAttributes & Props,
"ref" | "key">'.
I'm new learner of reactjs with typescript and I follow the https://www.youtube.com/watch?v=8jHKBAPNtpM tutorial for learning, but things are not explained properly on this video.
Can Anyone help me for resolve this issue.
My HomePage.tsx file
import React, { Component } from "react";
import Layout from "../../components/common/layout";
import Content from "../../components/common/content";
import Home from "./../../components/home";
class HomePage extends Component {
render() {
return (
<div className="wrapper">
<Layout>
<Content title="Dashboard">
<Home />
</Content>
</Layout>
</div>
);
}
}
export default HomePage;
my Layout.tsx file
import React, { Component } from "react";
import { connect } from "react-redux";
import TopNav from "../topnav";
import Aside from "../aside";
import UserStateInterface from "../../../interfaces/UserStateInterface";
import UserService from "../../../services/UserService";
import { setUser } from "./../../../store/actions";
interface Props {
user: UserStateInterface;
setUser: typeof setUser;
}
class Layout extends Component<Props> {
async componentDidMount() {
const response = await UserService.getCurrentUserProfile();
this.props.setUser(response);
}
render() {
return (
<React.Fragment>
<TopNav />
<Aside user={this.props.user} />
{this.props.children}
</React.Fragment>
);
}
}
const mapStateToProps = (state) => {
return {
user: state.user,
};
};
export default connect(mapStateToProps, { setUser })(Layout);
my Content.tsx file
import React, { Component } from "react";
interface Props {
title: String;
}
class Content extends Component<Props> {
render() {
const { title } = this.props;
return (
<div className="content-wrapper">
<section className="content-header">
<div className="container-fluid">
<div className="row mb-2">
<div className="col-sm-6">
<h1>{title}</h1>
</div>
<div className="col-sm-6">
<ol className="breadcrumb float-sm-right">
<li className="breadcrumb-item">
<a href="/" onClick={(event) => event.preventDefault()}>
Home
</a>
</li>
<li className="breadcrumb-item active">Blank Page</li>
</ol>
</div>
</div>
</div>
</section>
<section className="content">{this.props.children}</section>
</div>
);
}
}
export default Content;
my Home.tsx file
import React, { Component } from "react";
import Card from "./../common/card";
import TopCards from "./topcards";
import TodoWrapper from "../todo/todowrapper";
class Home extends Component {
render() {
return (
<React.Fragment>
<TopCards />
<div className="row">
<div className="col-md-6">
<TodoWrapper />
</div>
<div className="col-md-5">
<Card title="Some content will come" titleIcon="ion-clipboard">
<p>Content will come.</p>
</Card>
</div>
</div>
</React.Fragment>
);
}
}
export default Home;
You need to tell react that the component is ready to accept children.
React provides a utility for exactly this. Just replace your interface Props {...} with type Props = PropsWithChildren<{...}>.
import { PropsWithChildren } from "react";
type Props = PropsWithChildren<{
user: UserStateInterface;
setUser: typeof setUser;
}>;
Example: https://codesandbox.io/s/boring-chatelet-kp5vm?file=/src/Layout.tsx
I am adding a props of sidebar Component to my template.
I am passing {...this.props} to Sidebar.
But it still leads to TypeError: Cannot read property 'map' of undefined in my Menu file.
My PostTemplateDetails file that I wish to add the Sidebar component:
import React from 'react'
import Sidebar from '../Sidebar'
import { Link } from 'gatsby'
import moment from 'moment'
import './style.scss'
class PostTemplateDetails extends React.Component {
render() {
const { subtitle, author } = this.props.data.site.siteMetadata
const post = this.props.data.markdownRemark
const tags = post.fields.tagSlugs
const tagsBlock = (
<div className="post-single__tags">
<ul className="post-single__tags-list">
{tags &&
tags.map((tag, i) => (
<li className="post-single__tags-list-item" key={tag}>
<Link to={tag} className="post-single__tags-list-item-link">
{post.frontmatter.tags[i]}
</Link>
</li>
))}
</ul>
</div>
)
return (
<div>
<Sidebar {...this.props} />
<div className="content">
<div className="content__inner">
<div className="post-single">
<div className="post-single__inner">
<h1 className="post-single__title">{post.frontmatter.title}</h1>
<div
className="post-single__body"
/* eslint-disable-next-line react/no-danger */
dangerouslySetInnerHTML={{ __html: post.html }}
/>
<div className="post-single__date">
<em>
Published {moment(post.frontmatter.date).format('D MMM YYYY')}
</em>
</div>
</div>
<div className="post-single__footer">
{tagsBlock}
<hr />
<p className="post-single__footer-text">
{subtitle}
<a
href={`https://twitter.com/${author.twitter}`}
target="_blank"
rel="noopener noreferrer"
>
<br /> <strong>{author.name}</strong> on Twitter
</a>
</p>
</div>
</div>
</div>
</div>
</div>
)
}
}
export default PostTemplateDetails
My Sidebar component file:
import React from 'react'
import get from 'lodash/get'
import { Link } from 'gatsby'
import Menu from '../Menu'
import Links from '../Links'
import profilePic from '../../pages/photo.jpg'
import './style.scss'
class Sidebar extends React.Component {
render() {
const { location } = this.props
const {
author,
subtitle,
copyright,
menu,
} = this.props.data.site.siteMetadata
const isHomePage = get(location, 'pathname', '/') === '/'
/* eslint-disable jsx-a11y/img-redundant-alt */
const authorBlock = (
<div>
<Link to="/">
<img
src={profilePic}
className="sidebar__author-photo"
width="75"
height="75"
alt={author.name}
/>
</Link>
{isHomePage ? (
<h1 className="sidebar__author-title">
<Link className="sidebar__author-title-link" to="/">
{author.name}
</Link>
</h1>
) : (
<h2 className="sidebar__author-title">
<Link className="sidebar__author-title-link" to="/">
{author.name}
</Link>
</h2>
)}
<p className="sidebar__author-subtitle">{subtitle}</p>
</div>
)
/* eslint-enable jsx-a11y/img-redundant-alt */
return (
<div className="sidebar">
<div className="sidebar__inner">
<div className="sidebar__author">{authorBlock}</div>
<div>
<Menu data={menu} />
<Links data={author} />
<p className="sidebar__copyright">{copyright}</p>
</div>
</div>
</div>
)
}
}
export default Sidebar
My Menu component file, which is added in the Sidebar component file - this is where the error seems to be residing.
import React from 'react'
import { Link } from 'gatsby'
import './style.scss'
class Menu extends React.Component {
render() {
const menu = this.props.data
const menuBlock = (
<ul className="menu__list">
{menu.map(item => (
<li className="menu__list-item" key={item.path}>
<Link
to={item.path}
className="menu__list-item-link"
activeClassName="menu__list-item-link menu__list-item-link--active"
>
{item.label}
</Link>
</li>
))}
</ul>
)
return <nav className="menu">{menuBlock}</nav>
}
}
export default Menu
I am not sure why this is not working, since adding in my PAGETemplateDetails file seem to be working fine:
import React from 'react'
import Sidebar from '../Sidebar'
import './style.scss'
class PageTemplateDetails extends React.Component {
render() {
const page = this.props.data.markdownRemark
return (
<div>
<Sidebar {...this.props} />
<div className="content">
<div className="content__inner">
<div className="page">
<h1 className="page__title">{page.frontmatter.title}</h1>
<div
className="page__body"
/* eslint-disable-next-line react/no-danger */
dangerouslySetInnerHTML={{ __html: page.html }}
/>
</div>
</div>
</div>
</div>
)
}
}
export default PageTemplateDetails
SiteMetadata.menu is queried on the Post template File:
import React from 'react'
import Helmet from 'react-helmet'
import { graphql } from 'gatsby'
import Layout from '../components/Layout'
import PostTemplateDetails from '../components/PostTemplateDetails'
class PostTemplate extends React.Component {
render() {
const { title, subtitle } = this.props.data.site.siteMetadata
const post = this.props.data.markdownRemark
const { title: postTitle, description: postDescription } = post.frontmatter
const description = postDescription !== null ? postDescription : subtitle
return (
<Layout>
<div>
<Helmet>
<title>{`${postTitle} - ${title}`}</title>
<meta name="description" content={description} />
</Helmet>
<PostTemplateDetails {...this.props} />
</div>
</Layout>
)
}
}
export default PostTemplate
export const pageQuery = graphql`
query PostBySlug($slug: String!) {
site {
siteMetadata {
title
subtitle
copyright
author {
name
twitter
}
disqusShortname
url
}
}
markdownRemark(fields: { slug: { eq: $slug } }) {
id
html
fields {
tagSlugs
}
frontmatter {
title
tags
date
description
}
}
}
`
Not sure if this is relevant but this is the post file:
import React from 'react'
import { Link } from 'gatsby'
import moment from 'moment'
import './style.scss'
class Post extends React.Component {
render() {
const {
title,
date,
category,
description,
} = this.props.data.node.frontmatter
const { slug, categorySlug } = this.props.data.node.fields
return (
<div className="post">
<div className="post__meta">
<time
className="post__meta-time"
dateTime={moment(date).format('MMMM D, YYYY')}
>
{moment(date).format('MMMM YYYY')}
</time>
<span className="post__meta-divider" />
<span className="post__meta-category" key={categorySlug}>
<Link to={categorySlug} className="post__meta-category-link">
{category}
</Link>
</span>
</div>
<h2 className="post__title">
<Link className="post__title-link" to={slug}>
{title}
</Link>
</h2>
<p className="post__description">{description}</p>
<Link className="post__readmore" to={slug}>
Read
</Link>
</div>
)
}
}
export default Post
You're passing the property data as "menu" <Menu data={menu} />
In the Menu component, you don't have the menu property, you have this.props.data, which is equal to menu value, as defined in the Sidebar component. Probably there's no such property "menu" on this.props.data
So your code should be const data = this.props or const menu = this.props.data if you want to keep the variable name.
Thank you everyone, it was a query problem as ksav suspected. The Menu and Sidebar components were fine. I failed to query the menu information in my sitemetadata, and was able to fix it by going to my Post Template File and querying the menu, like so:
export const pageQuery = graphql`
query PostBySlug($slug: String!) {
site {
siteMetadata {
title
subtitle
copyright
menu {
label
path
}
author {
name
twitter
}
disqusShortname
url
}
}
markdownRemark(fields: { slug: { eq: $slug } }) {
id
html
fields {
tagSlugs
}
frontmatter {
title
tags
date
description
}
}
}
`
Thank you everyone, I'm struggling but I got there.
I am a beginner in React js and I'm trying to implement Context Provider in React js. But while I'm not getting the perfect output.
I am storing contact info in context.js which will act as Context Provider and in App.js I imported it in App.js then in Contacts.js I Consumed the Consumer and got the value but still, I'm getting the blank page and I'm not sure why I cannot bind the contact component in Context provider
Context.js
import React, {Component} from 'react';
const Context = React.createContext();
export class Provider extends Component {
state = {
contacts: [{
id: 1,
name: "dasd B",
email: "asdas#gmail.com",
phone: "dsadas"
}
};
render() {
debugger
return (
<Context.Provider value={this.state}>
{this.props.childern}
</Context.Provider>
);
}
}
export const Consumer = Context.Consumer;
App.js
import React, { Component } from 'react';
import Header from './components/Header';
import Contacts from './components/Contacts'
import 'bootstrap/dist/css/bootstrap.min.css';
import { Provider } from './Context'
class App extends Component {
render() {
return (
<Provider>
<div className="App">
<div className="container">
<Contacts />
</div>
</div>
</Provider>
);
}
}
export default App;
Contacts.js
import React, { Component } from 'react'
import Contact from './Contact';
import { Consumer } from '../Context';
class Contacts extends Component {
deleteContact = id => {
const { contacts } = this.state;
const newContacts = contacts.filter(contact => contact.id!== id);
this.setState({
contacts: newContacts
});
};
render() {
debugger
return(
<Consumer>
{value => {
const { contacts } = value;
return (
<React.Fragment >
{contacts.map(contact => (
<Contact
key = {contact.id}
contact={contact}
deleteClickHandler = {this.deleteContact.bind(this, contact.id)}>
</Contact>
))}
</React.Fragment>
);
}}
</Consumer>
);
}
}
export default Contacts;
Contact.js
import React, { Component } from 'react'
import PropTypes from 'prop-types'
class Contact extends Component {
state = {
showContactinfo : false
};
onDeleteClick = () => {
this.props.deleteClickHandler();
}
onEditClick() {
}
render() {
const { name, email, phone } =this.props.contact;
const { showContactinfo } = this.state;
return (
<div className="card card-body mb-3">
<h4>{name}
{showContactinfo ? (
<div className="float-right">
<i
onClick= {this.onEditClick}
style={{cursor: 'pointer', fontSize: 'medium'}}
className="fas fa-edit mr-3"></i>
<i
onClick= {this.onDeleteClick}
style={{cursor: 'pointer', fontSize: 'medium'}}
className="fa fa-trash-alt"></i>
</div>):
<i className="fa fa-sort-down float-right"
style={{cursor: 'pointer'}}
onClick={() =>
this.setState({ showContactinfo: !this.state.showContactinfo})}></i>}
</h4>
{showContactinfo ? (
<ul className="list-group">
<li className="list-group-item">Email: {email}</li>
<li className="list-group-item">Phone: {phone}</li>
</ul>) : null}
</div>
)
}
}
Contact.propTypes = {
contact: PropTypes.object.isRequired,
deleteClickHandler: PropTypes.func.isRequired
}
export default Contact;
I have 2 components 1)Content 2)Pagination
When I click on view stats button (see in screenshot) rendermatchinfo() method gets called and it shows details of single match and also shows pagination which should not be shown. Pagination must be shown only on home page where content component renders match details of all matches and not single match.
content.js :
import React, { Component } from 'react';
import Matchinfo from './matchinfo';
import './content.css';
class Content extends Component {
constructor(props){
super(props);
this.state = {
matches:[],
loading:true,
callmatchinfo: false,
matchid:''
};
}
componentDidMount(){
fetch('api/matches')
.then(res => res.json())
.then(res => {
console.log(res)
this.setState({
matches:res,
loading:false
});
})
}
viewstats(matchid){
this.setState({
callmatchinfo: true,
matchid: matchid
});
}
rendermatchinfo(){
return <Matchinfo matchid={this.state.matchid} />
}
renderMatches() {
return this.state.matches.slice(this.props.start, this.props.end).map(match => {
return (
<div className="col-lg-3">
<div id="content">
<p className="match">MATCH {match.id}</p>
<h4>{match.team1}</h4>
<p>VS</p>
<h4>{match.team2}</h4>
<div className="winner">
<h3>WINNER</h3>
<h4>{match.winner}</h4>
</div>
<div className="stats">
<button type="button" onClick= {()=>{this.viewstats(match.id)}} className="btn btn-success">View Stats</button>
</div>
</div>
</div>
);
})
}
render() {
if (this.state.loading) {
return <div>Loading...</div>
}
else if(this.state.callmatchinfo){
return <Matchinfo match_id={this.state.matchid} />
}
return (
<div>
<div className="row">
{this.renderMatches()}
</div>
<div className="row">
{this.state.callmatchinfo ? this.rendermatchinfo() : ''}
</div>
</div>
);
}
}
export default Content;
pagination.js:
import React, { Component } from 'react';
class Pagination extends Component {
handleClick(val){
this.setState({
end:val*16,
start:end-16
});
const end = val*16;
this.props.onChange(end - 16, end);
}
render() {
return (
<div>
<div className="container">
<ul className="pagination">
<li><a href="#" onClick={this.handleClick.bind(this, 1)}>1</a></li>
<li><a href="#" onClick={this.handleClick.bind(this, 2)}>2</a></li>
<li><a href="#" onClick={this.handleClick.bind(this, 3)}>3</a></li>
<li><a href="#" onClick={this.handleClick.bind(this, 4)}>4</a></li>
<li><a href="#" onClick={this.handleClick.bind(this, 5)}>5</a></li>
</ul>
</div>
</div>
);
}
}
export default Pagination;
Pagination and content component are imported in layout component.
layout.js :
import React, { Component } from 'react';
import Pagination from './pagination';
import Content from './content';
class Layout extends Component {
constructor(props){
super(props);
this.state = {
start:0,
end:16,
};
}
onChangePagination = (start, end) => {
this.setState({
start,
end
});
};
render() {
const {start, end} = this.state;
return (
<div>
<Content start={start} end={end}/>
<Pagination onChange={this.onChangePagination}/>
</div>
);
}
}
export default Layout;
Screenshot:
Home page which shows pagination :
When I click on view stats button of any particular match it still shows pagination but it should not show it.
move Pagination to Content component
Layout.js
import React, { Component } from 'react';
import Content from './content';
class Layout extends Component {
render() {
return (
<div>
<Content />
</div>
);
}
}
export default Layout;
Content.js
import React, { Component } from 'react';
import Matchinfo from './matchinfo';
import './content.css';
import Pagination from './pagination';
class Content extends Component {
constructor(props) {
super(props);
this.state = {
matches: [],
loading: true,
callmatchinfo: false,
matchid: '',
start: 0,
end: 16,
};
}
componentDidMount() {
fetch('api/matches')
.then(res => res.json())
.then(res => {
console.log(res)
this.setState({
matches: res,
loading: false
});
})
}
onChangePagination = (start, end) => {
this.setState({
start,
end
});
};
viewstats(matchid) {
this.setState({
callmatchinfo: true,
matchid: matchid
});
}
rendermatchinfo() {
return <Matchinfo matchid={this.state.matchid} />
}
renderMatches() {
return this.state.matches.slice(this.state.start, this.state.end).map(match => {
return (
<div className="col-lg-3">
<div id="content">
<p className="match">MATCH {match.id}</p>
<h4>{match.team1}</h4>
<p>VS</p>
<h4>{match.team2}</h4>
<div className="winner">
<h3>WINNER</h3>
<h4>{match.winner}</h4>
</div>
<div className="stats">
<button type="button" onClick={() => { this.viewstats(match.id) }} className="btn btn-success">View Stats</button>
</div>
</div>
</div>
);
})
}
render() {
if (this.state.loading) {
return <div>Loading...</div>
}
else if (this.state.callmatchinfo) {
return <Matchinfo match_id={this.state.matchid} />
}
return (
<div>
<div className="row">
{this.renderMatches()}
{!this.state.callmatchinfo && <Pagination onChange={this.onChangePagination} />}
</div>
<div className="row">
{this.state.callmatchinfo ? this.rendermatchinfo() : ''}
</div>
</div>
);
}
}
export default Content;
You should remove Pagination component from Layout component. Content component can be renamed as Matches component. Within the Matches component, show the Pagination component.
When view stat is clicked, show the MatchInfo component and hide the Matches and Pagination component.
I need is to display selected product details, I am using React and Redux:
After selecting one product, in my ProductDetails page should be shown details of selected product. How should I properly make it in order to get and show product details
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { asyncConnect } from 'redux-connect';
import { connect } from 'react-redux';
import * as productActions from 'redux/modules/products';
#asyncConnect([{
promise: ({ store: { dispatch, getState }, params }) => {
dispatch(productActions.load({ id: params.prodId }, getState()));
}
}])
#connect(
state => ({
products: state.products.items
}),
{
...productActions
}
)
export default class ProductDetails extends Component {
static propTypes = {
products: PropTypes.array.isRequired
};
static defaultProps = {
products: []
};
state = {
products: []
}
render() {
const { products } = this.props;
return (
<div className="container">
<div className="row">
<div className="col-md-12">
<h1>Product details</h1>
<div className="col-xs-12">
<div className="row">
<div className="col-xs-4">
<div className="panel panel-default">
<div className="panel-body">
<p>{products.name}</p>// show selected product name
<p>{products.description}<p> // show selected product description
</div>
))}
</div>
</div>
</div>
</div>
</div>
</div>
</div>
);
}
}
I managed to solve the problem, it was very easy:
{products[0].name}
and
{products[0].description}