Hi,
this is my code in react js
I want to show my blog posts on single page on clicking read more button I pick this url from
news api and i want to show every pot by its specific id but i use url as id
import React, { Component } from "react";
import BlogPage from "./BlogPage";
import propTypes from "prop-types";
import InfiniteScroll from "react-infinite-scroll-component";
export default class blogPost extends Component {
static defaultProps = {
category: "general",
};
static propTypes = {
category: propTypes.string,
};
constructor(props) {
super(props);
this.state = {
articles: [],
};
/* document.title = `${this.props.category}-news `; */
}
async componentDidMount() {
let url =
let data = await fetch(url);
let parsData = await data.json();
console.log(parsData);
this.setState({
articles: parsData.articles,
totalResults: parsData.totalResults,
});
}
getMorePost = async () => {
let url =
let data = await fetch(url);
let parsData = await data.json();
console.log(parsData);
this.setState({ articles: this.state.articles.concat(parsData.articles) });
};
render() {
return (
<div>
<div className="container">
{/* <span style={{ color: "grey" }}>
Blogs
<span style={{ fontWeight: "500", color: "black" }}>
- {this.props.category}
</span>
</span> */}
<InfiniteScroll
dataLength={this.state.articles.length}
next={getMorePost}
hasMore={this.state.articles.length !== this.state.totalResults}
loader={<h3> Loading...</h3>}
endMessage={<h4>Nothing more to show</h4>}
>
<div className="row pt-3.">
{this.state.articles.map((element) => {
return (
<div className={this.props.BlogClass} key={element.url}>
<BlogPage
CardClass={this.props.ClassCard}
ClassDes={this.props.DesClass}
ClassTitle={(this.props.TitleClass, " heading-blog")}
CardBody={this.props.BodyCard}
imgStyle={this.props.styleImg}
CardStyle={{
width: "100%",
height: "100%",
padding: "10px 0",
border: "none",
}}
title={element.title ? element.title.slice(0, 45) : ""}
description={
element.description
? element.description.slice(0, 90)
: ""
}
author={
/* element.author? element.author.slice(0, 5) : "" */
element.category
}
img={element.urlToImage}
/>
</div>
);
})}
</div>
</InfiniteScroll>
</div>
</div>
);
}
}
I want to show this posts on this page by clicking the read more button i try it several times but don't understand it
import React, { useState, useEffect } from "react";
import BlogPost from "./BlogPost";
export default function Blogpreview() {
/* const [blog,setBlog]=useState()
useEffect(() => {
let blog = articles.find((blog) => blog.id === parseInt(id));
if (blog) {
setBlog(blog);
}
}, []) */
/* const [blog,setBlog]=useState(null)
useState = async () =>{
let url =
let data = await fetch(url);
let parsData = await data.json();
console.log(parsData);
setBlog({ articles: parsData.articles,
totalResults: parsData.totalResults
});
}
*/
return (
<div className="container-fluid">
<div className="col-6 BlogPreviewBox px-5 ">
<div className="d-flex justify-content-center">
<img className="display-blog-box my-5" src="/"></img>
</div>
<h1 className="blog-preview-heading">
Why invoicing are beneficial for your business{/* {blog.title} */}
</h1>
<div className="d-flex flex-column align-items-center">
<span className="text-center py-3">07 December 2021</span>
<button className="btn-blog-display">2 min read</button>
</div>
</div>
<div className="row display-blog-content-row">
{/* <div className="col-3">
{ <div>
<p >What is Olabooks?</p>
<div className="d-flex flex-column">
<span>How to add invoice in Olabooks?</span>
<span className="py-2">How to share invoice in Olabooks?</span>
</div>
<i className="far fa-heart"></i>
</div>}
</div> */}
<div className="col-6">
<div className="d-flex flex-column display-blog-text">
<div>
<span>
Businesses that adopt advanced technologies are more likely to
thrive in the long run because of the rapid response to modern
techniques and innovation. Many questions need to be taken into
account while adopting advanced technology, but most
importantly, you begin to think about the values it must provide
to you and your business. It is not an easy task toruna
business, especially in this tech-savvy world. Let's dig into
some commercial benefits of moving from pen and paper invoicing
to efficient e-invoicing that would make headway for your
business.
</span>
</div>
</div>
<div className="tag-display-blog">
<div>
<strong>By Olabooks</strong>
<span>author</span>
</div>
</div>
</div>
{/* <div className="col-3">
<div>
<span>Related</span>
</div>
<div className="displa-related-blog">
<h5 className="py-2">Why is e-invoicing beneficial for your business?</h5>
<span>
Business that adopt advanced technologies are more likely to thrive in the long run because of
</span>
<button className="btn-related-blog-display">9 min read</button>
</div>
</div> */}
</div>
</div>
);
}
I tried making API calls to the same URL, it seems that you are getting same API response in both cases (with and without pageSize param), due to which, your "read more" is actually not rendering any new content to the screen
(with the pageSize query parameter)
(without the pageSize parameter)
Also, it is better to not include your API key in the question
Related
So I'm attempting to redo a personal blog site that I built entirely in Django with the template system with a DRF / Next.js set up. The problem is that I can display the blog posts on the page no problem with and unpaginated django serializer. When I paginate the django serializer because I only want a few posts on the from page I get the error
TypeError: p.map is not a function
Here is the code that works:
import Head from 'next/head'
import Image from 'next/image'
import styles from '../styles/Home.module.css'
import React, { Component } from 'react'
import Header from '../components/header'
import Link from 'next/link';
function Home({ p }) {
return (
<React.Fragment>
<Header />
<header className="masthead">
<div className="container position-relative px-4 px-lg-5">
<div className="row gx-4 gx-lg-5 justify-content-center">
<div className="col-md-10 col-lg-8 col-xl-7">
<div className="site-heading">
<h1>test</h1>
<span className="subheading">Test subheading</span>
</div>
</div>
</div>
</div>
</header>
{p.map((post) => (
<div className="container px-4 px-lg-5" key={post.id}>
<div className="row gx-4 gx-lg-5 justify-content-center">
<div className="col-md-10 col-lg-8 col-xl-7">
<div className="post-preview">
<Link href={`/posts/${encodeURIComponent(post.slug)}`}>
<a><h2 className="post-title">{ post.title }</h2>
<h3 className="post-subtitle">{ post.article_body.substr(0,50)}</h3></a>
</Link>
<p className="post-meta">
Posted by { post.author } in { post.article_type }
on { post.date_posted }
</p>
</div>
</div>
</div>
</div>
))}
<div className='container'>
<hr className="my-4" />
<div className="d-flex justify-content-end mb-4"><a className="btn btn-primary text-uppercase" href="/allposts">All Posts →</a></div>
</div>
</React.Fragment>
)
}
export async function getStaticProps() {
const res = await fetch("https://www.api.com/api");
const p = await res.json();
console.log
return{
props: {
p
},
};
};
export default Home;
This code displays all blog entries that are in the database and works just fine.
As soon as I change the api address to the paginated version I get the error:
TypeError: p.map is not a function
This api is being paginated by Django Rest Framework serializer.
If anyone could help me here it would be great. I've been banging my head against the wall for the last two days trying to figure this out.
At first check does your api returns an array? if it says map is not a function that's for sure that p is not an array
When I clicked on the button "Buy", the store redux is updated and
push a new array to the initial state. But I don't see any new render
in the shop-cart section without leaving the page and go in again so I
can see new items. I'm new to React and Redux, I have been trying to fix it but it was not working and i'm very confused about it
Here is the reducer section
const initialState = {
counter : 0,
cartData : [
{
id : 1,
name : "Melon",
price : 100,
img : "https://d1hr6nb56yyl1.cloudfront.net/product-images/93368-280.jpg",
quantity : 1
},
{
id : 1,
name : "Melon",
price : 100,
img : "https://d1hr6nb56yyl1.cloudfront.net/product-images/93368-280.jpg",
quantity : 1
},
]
};
function cartNumber(state = initialState, action) {
console.log(state.cartData)
let cartIndex = [...state.cartData];
switch(action.type){
case "INCREMENT" :
return {
...state,
cartData : cartIndex.concat(action.newData)
};
break;
case "DECREMENT" :
default :
return state;
}
return cartIndex
}
export default cartNumber;
Here is the Item Detail page and Items Cart section
import React, {useEffect,useState} from "react";
import SubCart from "../components/SubCart";
import { useSelector, useDispatch } from "react-redux";
import {Link} from "react-router-dom";
function ItemDetail({match, history}){
const dispatch = useDispatch();
const [item, setItem] = useState({});
const scroll = () => {window.scroll(0,0)};
useEffect(() => {
const fetchItem = async () => {
const fetchItem = await fetch(
`https://5e5a9fc26a71ea0014e61f04.mockapi.io/api/${match.params.category}/${match.params.id}`
);
const item = await fetchItem.json();
setItem(item);
};
fetchItem();
scroll();
}, [])
const showRating = (rating) => {
var result = [];
for(var i = 1; i <= rating; i++){
result.push(<i className="fa fa-star" key={i + 1} style={{fontSize : ".8rem", color : "#ff4e00", padding : "0rem .1rem"}}></i>);
}
for (var j = 1; j <= (5-rating); j++) {
result.push(<i className="far fa-star" key={i + 1} style={{fontSize : ".8rem", padding : "0rem .1rem"}}></i>);
}
return result;
}
const backButton = () => {
history.goBack();
}
const showSubcart = () => {
let sub = document.getElementById("subcart-section");
let bg = document.getElementById("bg-ccc");
sub.classList.toggle("showSubCart");
bg.classList.toggle("bg-ccc");
dispatch({type : "INCREMENT", newData : item });
}
return (
<div style={{backgroundColor: "white"}}>
<div className="item-detail" style={{paddingBottom : "1rem"}}>
<div className="section-heading">
<div className="section-content">
<div className="icon-home">
<i className="fas fa-home"></i>
</div>
<div className="nav-home">
<Link to="/">Home</Link>
</div>
<div className="icon-to">
<i className="fas fa-chevron-right"></i>
</div>
<div className="nav-cart">
<Link to="/">{item.category}</Link>
</div>
</div>
</div>
<div className="img-detail">
<img src={item.img} alt={item.name} />
<span className="icon-section"><i className="far fa-heart"></i></span>
<span className="icon-section-arrow" onClick={() => backButton()}><i className="fas fa-arrow-left"></i></span>
</div>
<div className="item-detail-content">
<div className="container">
<Link to="/" style={{color : "black"}}><span className="category">{item.category}</span></Link>
<div><h2>{item.name}</h2></div>
<div><h3>{item.price}$</h3></div>
<div>
<ul>
<li>{showRating(item.rating)} <span style={{fontSize : ".8rem"}}>(210)</span></li>
</ul>
</div>
<div className="buy" onClick={() => showSubcart()}>
<span className="buy-text">Buy</span>
<span className="buy-icon"><i className="fas fa-shopping-cart"></i></span>
</div>
<div className="description">
<div className="head-description">
<h3><i className="far fa-bookmark"></i> Description</h3>
</div>
<div className="body-description">
<p>...</p>
</div>
</div>
<div className="infoPolicy mt-top">
<div className="box-head">
<i className="fas fa-truck"></i>
</div>
<div className="box-content">
<p className="note-p">FREE NATIONAL DELIVERY</p><span className="note">(Products over 50$)</span>
</div>
</div>
<div className="infoPolicy mt-top">
<div className="box-head">
<i className="fas fa-sync-alt"></i>
</div>
<div className="box-content">
<p className="note-p">Returns are Easy</p><span className="note">(Return 30days for items)</span>
</div>
</div>
<div className="infoPolicy mt-top mt-bt">
<div className="box-head">
<i className="fas fa-headset"></i>
</div>
<div className="box-content">
<p className="note-p">Telephone consultation</p><span className="note">(Free from 8:00 - 21:00 every day)</span>
</div>
</div>
</div>
</div>
<SubCart />
</div>
</div>
);
}
export default ItemDetail;
import React, {useState} from "react";
import {Link} from "react-router-dom";
import {useSelector} from "react-redux";
function ItemCart(){
let data = useSelector(state => state.cartData);
let [items, setItem] = useState(data);
return (
<div className="subcart-link">
{items.map((item, index) => (
<div className="d-flex" key={index}>
<div className="subcart-img">
<img src={item.img} alt="pubg"/>
</div>
<div className="subcart-item-content">
<Link to="/">{item.name}</Link>
<div className="subcart-item-detail">
<p>{item.price}$<span className="subcart-quantity">x 2</span></p>
</div>
</div>
<div className="delete-click">
<p>x</p>
</div>
</div>
))}
</div>
);
}
at your ItemCart you are duplicating redux state into a react state, which is not advisable. they are two different entities, though you can have both types at your application a given specific state should be handled by a specific state manager.
at your ItemCart remove useState altogether, and map over data variable instead. your issue comes from the fact that your items state inherits only the original redux state, but since they are different states, it doesnt get updated when redux state changes.
fwiw, dont use dom manipulation to handle classes like you do at showSubCart, this is not good. I suggest to use some boolean logic instead to toggle class, based on some props or state value.
Can anyone explain what's going on here?
On the index page referenced below there is a section where I source data from a WordPress API to generate the four most recent posts from a client. When running in develop mode with Gatsby, the website is presented fine, but when I upload the website to Netlify and build it out, the data disappears and leaves nothing more than an empty set of p tags.
When I go into development tools and step through breakpoints, I notice that the data in question appears on the website, but then disappears once the webpack fires and the modules are bundled. It's almost as if this data is getting overwritten. When I navigate away from this page on the same website, and then return, the p tags HAVE the data in question. I'm assuming the webpack overwrites the initial code, and then when I come back to the page the webpack has already fired so it loads the information fine? How do I work around this? Excuse me if this is a silly/obvious question.
Full code in reference:
import React from "react"
import { Link, graphql, useStaticQuery } from 'gatsby'
import Layout from '../components/layout'
import indexStyles from '../components/modules/index.module.css'
import Carousel from 'nuka-carousel'
import header1 from '../img/header1.jpg'
import header2 from '../img/header2.jpg'
import header3 from '../img/header3.jpg'
const IndexPage = () => {
const data = useStaticQuery(graphql`
query {
allWordpressPost (sort: {fields:date, order:DESC}) {
edges {
node {
title
slug
excerpt
date(formatString:"MMMM DD, YYYY")
}
}
}
}
`)
return (
<Layout>
<div className={indexStyles.indexCarousel_container}>
<Carousel
autoplay={true}
autoplayInterval={5000}
pauseOnHover={false}
wrapAround={true}
renderCenterLeftControls={({ previousSlide }) => (
<button onClick={previousSlide} className={indexStyles.indexCarousel_button}><i className="fas fa-arrow-left"></i></button>
)}
renderCenterRightControls={({ nextSlide }) => (
<button onClick={nextSlide} className={indexStyles.indexCarousel_button}><i className="fas fa-arrow-right"></i></button>
)}>
<div className={indexStyles.indexCarousel_slideContainer}>
<img src={header1} alt="Pencil case with cat, heart, and cupcake design."></img>
<div>
<h2>Shop</h2>
</div>
</div>
<div className={indexStyles.indexCarousel_slideContainer}>
<Link to="/blog"><img src={header2} alt="Notepad next to a cup of coffee."></img></Link>
<div>
<h2>Blog</h2>
</div>
</div>
<div className={indexStyles.indexCarousel_slideContainer}>
<img src={header3} alt="Colorful pencil cases."></img>
<div>
<h2>Cute Castle VIP</h2>
<p>Save 20%!</p>
</div>
</div>
</Carousel>
</div>
<h1 className={indexStyles.indexHeader}>Latest Posts</h1>
<div className={indexStyles.indexPost_container}>
<div className={indexStyles.indexPost_container}>
{data.allWordpressPost.edges.map((edge, i) => {
if (i < 4) {
return (
<div className={indexStyles.index_post}>
<h2><Link to={`/blog/${edge.node.slug}`} className={indexStyles.post_title} dangerouslySetInnerHTML={{ __html: edge.node.title }}></Link></h2>
<p className={indexStyles.post_date}>{edge.node.date}</p>
<p className={indexStyles.post_excerpt} dangerouslySetInnerHTML={{ __html: edge.node.excerpt }} />
<p><Link to={`/blog/${edge.node.slug}`} className={indexStyles.post_link}>Read more</Link></p>
</div>
)
}
})}
</div>
</div>
</Layout >
)
}
export default IndexPage
The section of code that disappears and reappears:
<div className={indexStyles.indexPost_container}>
<div className={indexStyles.indexPost_container}>
{data.allWordpressPost.edges.map((edge, i) => {
if (i < 4) {
return (
<div className={indexStyles.index_post}>
<h2><Link to={`/blog/${edge.node.slug}`} className={indexStyles.post_title} dangerouslySetInnerHTML={{ __html: edge.node.title }}></Link></h2>
<p className={indexStyles.post_date}>{edge.node.date}</p>
<p className={indexStyles.post_excerpt} dangerouslySetInnerHTML={{ __html: edge.node.excerpt }} />
<p><Link to={`/blog/${edge.node.slug}`} className={indexStyles.post_link}>Read more</Link></p>
</div>
)
}
})}
</div>
</div>
A link to the Netlify project.
https://zealous-engelbart-509321.netlify.com/
Thanks in advance for your help!
Newbie dev learning React.
I'm trying to create an upvote functionality to a blog post in React but when I click on the upvote button I'm upvoting all of the blog post cards at once instead of the individual card.
How can I fix this? I believe the issue may be in the way I'm setting setState? But I may be wrong and looking for help.
Thanks in advance!
====
class Posts extends Component {
state= {
points: 0
}
componentDidMount() {
this.props.fetchPosts()
}
UNSAFE_componentWillReceiveProps(nextProps) {
if (nextProps.newPost) {
this.props.posts.unshift(nextProps.newPost);
}
}
handleClick = () => {
this.setState({points: this.state.points + 1})
}
render() {
const postItems = this.props.posts.map((post, index) => (
<div key={index} className="ui three stackable cards">
<div className="ui card">
<div className="content">
<div className="header">{post.title}</div>
<div className="meta"> {post.author}</div>
<div className="description">
<p>{post.body}</p>
</div>
</div>
<div className="extra content">
<i className="check icon"></i>
{this.state.points} Votes
</div>
<button className="ui button"
type="submit"
onClick={this.handleClick}>Add Point</button>
</div>
</div>
))
return (
<div>
<br />
<h2 className="ui header">
<i className="pencil alternate icon"></i>
<div className="content">
Blog Feed
<div className="sub header">Create New Post!</div>
</div>
</h2>
{postItems}
</div>
)
}
}
You have a single component storing the "points" state for all your posts. To achieve the functionality you described, each post should be it's own component with it's own state.
class Post extends Component {
state = {
points: 0
}
handleClick = () => {
this.setState({points: this.state.points + 1})
}
render = () =>
<div key={index} className="ui three stackable cards">
<div className="ui card">
<div className="content">
<div className="header">{this.props.title}</div>
<div className="meta"> {this.props.author}</div>
<div className="description">
<p>{this.props.body}</p>
</div>
</div>
<div className="extra content">
<i className="check icon"></i>
{this.state.points} Votes
</div>
<button className="ui button"
type="submit"
onClick={this.handleClick}>Add Point</button>
</div>
</div>
}
}
You are upvoting every card because you have only one counter. A separate counter should be defined for every card.
state = {}; // dictionary-a-like state structure
handleClick = (id) => () => {
this.setState((prevState) => ({
[id]: prevState[id] ? prevState[id] + 1 : 1, // check and increment counter
}));
}
onClick={this.handleClick(post.id)} // call function with post.id as argument
{this.state[post.id] || 0} Votes // display votes for every card
Note: I assumed that every card has it's own unique id, if not - index may come handy too.
You will need one counter for each post. Currently you only have a single counter for all posts, which means that they all display that same value.
The best way to achieve this would probably be to separate your post into its own component, and have that keep track of the counter.
The following solution uses a post ID (if you have it) to create a key in a stateful points object. Then, on click, you can add to the correct points key.
state = {
points: {}
}
handleClick = postId => {
this.setState({
points: {
...this.state.points,
[postId]: (this.state.points[postId] || 0) + 1
}
})
}
const postItems = this.props.posts.map((post, index) => (
...
<div className="extra content">
<i className="check icon"></i>
{this.state.points[post.id] || 0} Votes
</div>
<button
className="ui button"
type="submit"
onClick={() => this.handleClick(post.id)}
>
Add Point
</button>
...
)
Task: add +1 to willWatch when <a> is clicked.
I have an error when <a> is clicked, because MovieItem is not a component. I try to set class MovieItem... but I have a problem with moviesData
import React, { Component } from "react";
import { moviesData } from "../moviesData";
function MovieItem(props) {
let {info : { id, vote_count , video, vote_average, title, popularity, poster_path, original_language, original_title ,backdrop_path, adult, overview} } = props;
return (
<div className="col" id={id} style={{width: "18rem"}}>
<img className="card-img-top" src={'https://image.tmdb.org/t/p/w500' + poster_path}
alt="Card image cap"/>
<div className="card-body">
<h5 className="card-title">Оригинальное название: {original_title}</h5>
<h5 className="card-title">Название: {title}</h5>
<p className="card-text">{overview}</p>
<p className="card-text">Рейтинг: {vote_average}</p>
<p className="card-text">Популярность: {popularity}</p>
<p className="card-text">Наличие видео: {video}</p>
<p className="card-text">Оригинальный язык: {original_language}</p>
<p className="card-text">Возраст 18+: {adult}</p>
<p className="card-text">backdrop_path {backdrop_path}</p>
<p className="card-text">Голоса: {vote_count}</p>
<a
// onClick={this.props.counter}
href="#"
className="btn btn-primary">Will Watch
</a>
</div>
</div>
)
}
class App extends Component {
constructor(state) {
super(state);
this.state = {
willWatch: 0
};
this.counter = this.counter.bind(this)
}
counter(e) {
e.preventDefault();
this.state.willWatch = this.state.willWatch + 1
}
render() {
return (
<div className="container">
<div className="col-12">
<div className="row">
<div className="col-9">
<div className="row">
{
moviesData.map((props) => {
return <MovieItem info={props} counter={this.counter}/>
})
}
</div>
</div>
<div className="col-3 sidebar">
<div className="row">
<p> Хочу посмотреть, фильмов: {this.state.willWatch} </p>
</div>
</div>
</div>
</div>
</div>
)
}
}
export default App;
First of all, you have to destructure count from props like so:
function MovieItem(props) {
let {info : { id, vote_count , video, vote_average, title, popularity, poster_path, original_language, original_title ,backdrop_path, adult, overview}, counter } = props;
return (
<div className="col" id={id} style={{width: "18rem"}}>
<img className="card-img-top" src={'https://image.tmdb.org/t/p/w500' + poster_path}
alt="Card image cap"/>
<div className="card-body">
<h5 className="card-title">Оригинальное название: {original_title}</h5>
<h5 className="card-title">Название: {title}</h5>
<p className="card-text">{overview}</p>
<p className="card-text">Рейтинг: {vote_average}</p>
<p className="card-text">Популярность: {popularity}</p>
<p className="card-text">Наличие видео: {video}</p>
<p className="card-text">Оригинальный язык: {original_language}</p>
<p className="card-text">Возраст 18+: {adult}</p>
<p className="card-text">backdrop_path {backdrop_path}</p>
<p className="card-text">Голоса: {vote_count}</p>
<a
onClick={counter}
href="#"
className="btn btn-primary">Will Watch
</a>
</div>
</div>
)
}
and one more note, you have to set state using setState function:
counter(e) {
e.preventDefault();
this.setState((prevState) => {
return {
willWatch: state.willWatch + 1
}
});
}
You should never mutate/set this.state value directly.
Or else React would not know whether state has been changed or not.
(Refer to this article for details).
So instead of updating willWatch directly,
counter(e) {
e.preventDefault();
this.state.willWatch = this.state.willWatch + 1
}
Use setState
counter(e) {
e.preventDefault();
this.state(prevState => ({willWatch: prevState.willWatch + 1}));
}