Nested subcomponents in React + rendering new data - reactjs

Help needed please,
I am currently learning react and I ran into an issues of some sort while creating a blog app.
I nested components within each other, however updated data is not received in subcomponent unless I refresh the page of the nested-component. Below is snippet of my codeWithin the AccountOverview component is another component(container) that handles a form. Once the form submits data and the backend processes the data, i expect that the AccountOverview component will render new info. However if i then go back to the parent (dashboard) and make an edit the AccountOverview component does't display newly created data except on a full-page refresh.
class Dashboard extends Component {
state = {}
componentDidMount(){
this.props.getCurrentProfile();
}
render() {
const { user } = this.props.auth;
const { profile, loading } = this.props.profile;
return (
<div style={{margin: "0", padding: "0"}}>
<Header title="Account Dashboard" />
<section id="accountPage" className="">
<div className="container">
<div className="row">
<Sidebar />
<main className="col-sm-9 col-md-9 account">
<div className="dashboard">
<AccountOverviewPanel
user={user} profile={profile} loading={loading}
/>
<PostTablePanel />
</div>
</main>
</div>
</div>
</section>
</div>
);
};
};

Is your submit action casusing your components to unmount.
I tried cloning your code. it seems to miss a file for keys hence couldn't run it

Related

How to solve react hydration error in Nextjs

I have created small nextjs page using wordpress REST API, Now react-hydration-error error show this page.I am using react html parser npm. How do I solve this error. could you please solve this error.
my code:
import Image from 'next/image'
import React ,{Component}from 'react'
import Link from 'next/link';
import { BiCalendar } from "react-icons/bi";
import ReactHtmlParser from 'react-html-parser';
export default class Blog extends Component{
constructor(props){
super(props);
this.state={
data: props.bloglist,
isLoading: true,
dataLoaded: false,
};
}
render(){
if (!this.state.data) {
return null;
}
console.log(this.state.data)
return(
<>
<div className="container blog-section">
<div className='row'>
<h2>Latest Posts</h2>
</div>
<div className='row'>
{
this.state.data.map(((x,i) =>(
<div className='col-md-4 boxs text-center' key={i}>
<div className='bg-info'>
<img src={x.images.large} className='img-fluid'/>
<h3>{x.title.rendered} </h3>
<p className='shopping'><span><BiCalendar/> {x.date}</span> </p>
{/* <p dangerouslySetInnerHTML={{__html: x.excerpt.rendered}}></p><span><BiShoppingBag/> {x.slug}</span> */}
<p class='expert'>{ReactHtmlParser(x.excerpt.rendered)}</p>
<Link href={"/blog"+"/"+x.slug+"/"+x.id } passHref={true}><p className='readmore'><span>Readmore </span></p></Link>
</div>
</div>
)))
}
</div>
</div>
</>
)
}
}
My original issues:
paragraph coming this format <p>If you have heard that there are ways to make money while shopping in the UAE and would lik</p> from API, So I converted to html.
I had this error, in my case I had <p> tag nested inside another <p> tag,
I was using Typography (MUI v5) to render text, switching to <Box> from <Typography> fixed the error.
We use components to build the React-based websites, These components are made using HTML tags. It is very important not to nest the same HTML elements.
For Example:
function Logo() {
return (
<Link href="/">
<a>
<Image
src="/images/logo.svg"
width={100}
height={75}
/>
</a>
</Link>
);
}
export default Logo;
Above is the Logo Component which has already the <a></a> tag inside it.
In this example, you will get the React Hydration Error if the <a> tag is used inside another <a> tag.
<a href="#">
<Logo />
</a>
So do not include the same HTML tags, which are hidden inside the
components to avoid react hydration error.
In my case I am using NextJS and I had a dropdown with react-select, the default value was changing after a small calculation, that does not like to nextjs, this is my previous code:
<Select options={seasons}
onChange={() => setSeason(e.value)}
defaultValue={seasons.find((x) => x.value == season) ? seasons.find((x) => x.value == season) : seasons[0]}
/>
So, I changed that calculation to the useEffect and initialized the react-select dropdown only when that value was calculated,now this is my current code that works:
{defaultSeason && (<Select options={seasons}
onChange={() => setSeason(e.value)}
defaultValue={defaultSeason}
/>)}
So, basically check that the defaultValue or anything else does not change after the html is sent to the client part in NextJS.
Follow these: https://nextjs.org/docs/messages/react-hydration-error
Or try deleting <a> within <Link> maybe.
My first code was this:
const isUserLoggedIn = is_user_logged_in()
// is_user_logged_in() checks for cookie of user token and returns boolean
Got the error about hydration
Then changed code to this:
const [isUserLoggedIn, setIsUserLoggedIn] = useState(null)
useEffect(() => {
setIsUserLoggedIn(is_user_logged_in())
}, [])
Renders was like this:
{isUserLoggedIn ? (
<>
{/* After login */}
<Profile USER={USER}/>
</>
) : (
<>
{/* Before login */}
<SigninButtons/>
</>
)}
And error solved
You can also check this
https://nextjs.org/docs/messages/react-hydration-error
Just try restarting the server. npm run dev. It worked for me. I was using react-hot-toaster.
Also try to check if you have sth like this:
<p>
<div>
Hello
</div>
</p>
div cant be inside p tag

How to NOT render/ hide a React component when no prop is passed?

TLDR: Cannot figure out why component is still being rendered while no props are passed.
So I have been building a NextJS application, and I have this banner component that is shown on every page of my website. It has some header text, buttons and an image:
const Banner = (props) => {
return (
<div className={bannerStyles.wrapper}>
<div className={classnames(bannerStyles.banner, "wrap", "center")}>
<div className={bannerStyles.banner_left}>
<h1>{props.header}</h1>
<div className={bannerStyles.button_wrapper}>
<div className={bannerStyles.button}>
<Button>{props.button || null}</Button>
</div>
<div className={bannerStyles.button}>
<Button>{props.scnd_button || null}</Button>
</div>
</div>
</div>
<div className={bannerStyles.banner_right}>
<Image src={props.image} alt=""></Image>
</div>
</div>
</div>
);
};
Inside of this, as you can see I have two Button components (The MDEast thing is an arrow icon):
const Button = ({children}) => {
return (
<div className={buttonStyles.button}>
<Link href="/"><a>{children} <MdEast /></a></Link>
</div>
)
}
Now I want the option that if no prop is passed, that the Button component(s) do(es) not render/ is hidden from the page, so that it is optional per page. Yet the Button does still render, even though I am not passing any props on my About page. My about page:
const About = () => {
return (
<>
<Banner
header="Hello this is my code"
image={banner_placeholder}
/>
</>
)
}
PS. I am fairly new to React and NextJS, so this might be a beginner mistake, or I am not understanding the fundamentals well enough, but could someone point me in the right direction please?
To conditionally render the button you can use:
props.button && <Button>{props.button}</Button>
When props.button is falsy, then button will not get rendered.

Reactjs component - one vs many

I'm new to react and I'm trying to figure out the best way to make a component that can handle different scenarios. I'm not sure if the best practice would be to make multiple components or one component to handle it all.
Imagine a frontpage were you have 3 different entrances like recent products, blogpost or Instagram pictured. Each entrance use a component called featured and inside that component I should render either products, blogpost or Instagram pictures. Everything for the layout is the same, its just the items in the grid that needs to change. What would be the best way to solve this? one component with 3 different sub-components or 3 components with one for each type.
I know how to make 3 different components, but I'm not sure how to make one component to handle subcomponents.
This could be the component and the "grid-item--product" could also be a "grid-item--blogpost or "grid-item--Instagram" - "grid" could also be a "two-col" or "three-col".
<div className="featured">
<div className="featured--content">
<div className="grid four-col">
<grid-item--product />
</div>
</div>
</div>
and this could be where I would call the component and hopefully be able to handle which component should be rendered inside and what the grid should be for this feature.
<div className="frontpage-route">
<h2>Frontpage Route</h2>
<Featured />
</div>
Can you help me? I would love an example if possible.
Thanks.
It sounds like what you want is the children prop. You can add the children prop to Featured and just pass the correct children to it. See an example here:
const Featured = ({ children, numColumns = "one" }) => (
<div className="featured">
<div className="featured--content">
<div className={`grid ${numColumns}-col`}>
{children}
</div>
</div>
</div>
)
const App = () => (
<div className="frontpage-route">
<h1>Frontpage Route</h1>
<h2>Products</h2>
<Featured numColumns="two">
<grid-item--product />
<grid-item--product />
</Featured>
<h2>Blogs</h2>
<Featured numColumns="three">
<grid-item--blog />
<grid-item--blog />
</Featured>
<h2>Instagram</h2>
<Featured>
<grid-item--instagram />
<grid-item--instagram />
</Featured>
</div>
)
You can use consitional rendering and three boolean variables to display components.
e.g:
<div className="featured">
<div className="featured--content">
<div className="grid four-col">
{product && <grid-item--product />} //if product var is true this component renders
{blogpost && <grid-item--blogpost />} //if blogpost var is true this component renders
{instagram && <grid-item--instagram />} //if instagram var is true this component renders
</div>
</div>
</div>

React returns my mapped-over array data out of order

In my main component App.js, I have an array of data received from a redux store that looks like this:
[
{...}, {...}
]
Each object in the array contains information about a post (like a reddit post) that I map over to display as a preview card. Upon clicking that preview card, a modal card will display with a detailed view of the post.
// From App.js:
return (
<div className="entirePostList">
<NavBar />
<div className="postListContainer">
<div className="postListRow">
{posts.map((post) => (
<div key={post.id} onClick={this.openDetailsPostModal}>
<PostCard post={post} />
</div>
))}
</div>
</div>
<button className="newPostButton"
onClick={this.openCreatePostModal}>
<MdAddCircle />
</button>
<Modal // VIEW POST DETAILS MODAL
className='modal'
overlayClassName='createOverlay'
isOpen={detailsPostModalOpen}
onRequestClose={this.closeDetailsPostModal}
contentLabel='Modal'
>
<div>
{loadingDetailsPost === true
? <div>
<div className="postEditorBg" />
<Loading type='bubbles'
delay={200}
color='#fed80a'
className="loading"
width={120} />
</div>
: <div>
<div className="postEditorBg" />
<PostCardDetails />
</div>
}
</div>
</Modal>
In the <PostCardDetails /> component, I am receiving the same array of data from the redux store and mapping over it in the same way to display the data as UI. It displays correctly, but the problem is when I click a card preview, it displays the wrong detailed card (not the one you would expect based on the preview).
Here's the github repo in case more context is needed.
I'm beyond stuck on this - person who can answer this shall receive love and respect for eternity.

Pass props to props.history.push('path') in ReactJS

BACKGROUND
I am attempting to learn ReactJS by building my first Single Page Application. I usually work in .NET MVC, and I'm coming across some difficulties in the thought process required for SPAs. Anyways, I am using the latest version of React & React Router. Here is what I have at the moment.
CODE
So far, I have 5 true components in total. Here they are in order of usage:
App
ArtistList
Loops over artist array (coming from a local variable so far) and draws Artistcards
ArtistCard
Artist
Think of this as the detailed view of an artist. You get here by clicking an ArtistCard (shown in screenshot) so that you can see the list of LyricCards
LyricCard
My routes are declared in my [App component]. Here is the JSX for that.
<div className="App">
<Header />
<Route exact path="/" render={routeProps => <ArtistList {...routeProps} artists={artists} />} />
<Route exact path="/artist/:artistUrlName" component={Artist} />
</div>
Here is the code for my [ArtistList component]:
class ArtistList extends Component {
render() {
return (
<div className="artist-list">
{this.props.artists.map(artist =>
<ArtistCard key={artist.imageUrl} artist={artist} history={this.props.history} />
)}
</div>
);
}
}
Here is the code for my [ArtistCard component]:
class ArtistCard extends Component {
constructor() {
super();
this.navigateToArtist = this.navigateToArtist.bind(this);
}
navigateToArtist() {
this.props.history.push(`/artist/${this.props.artist.urlFriendlyName}`);
}
render() {
return (
<div
className="artist-card"
onClick={() => {
this.navigateToArtist();
}}
>
<div className="artist-image">
<img src={this.props.artist.imageUrl} alt="artist" />
</div>
<div className="artist-name">
<h3>
{this.props.artist.name}
</h3>
</div>
<div className="artist-meta">
<div className="artist-lyrics">
<h4>
{this.props.artist.lyricsCount}
</h4>
</div>
<div className="artist-hearts">
<h4>
{this.props.artist.likesCount}
</h4>
</div>
</div>
</div>
);
}
}
PROBLEM
When clicking an artist card (e.g. James Brown), I am able to navigate to the route /artist/james-brown, but I don't know how I can pass the data (the props) required by the [Artist component] (which will show a list of lyric cards).
As mentioned, this is my first ever SPA, and I am not sure if I'm going about this the right way. As a developer, I know I can grab the urlFriendlyName from the URL and pass that to an API endpoint that would get me a list of the lyrics (and other stuff I may need), and I can then set those on the state of the component via one a relevant component life-cycle mount method.
But is that the way with SPAs? I mean another way I can do this would be to make a single call to the API endpoint in my controller / parent [App component] and get all artists and their lyrics and everything else I need? I'll still need you to tell me how I can then pass the artist data and all his/her lyrics via props to the [Artist component].

Resources