Display/delete component on click - javascript

So, im trying to display my component named documentReader inside div with class desktop-app-grid by clicking and icon below, but icon is also a component, i tried doing this by using state, but i don't know how I can do this. I'm dropping my code below with hope someone can help me.
I got this:
<div className="desktop">
<div
className="desktop-app-grid"
>
</div>
<div className="taskbar">
<div className="taskbar-content">
<div className="apps">
<TaskbarAppIcon
appName="documentReader"
icon={icon}
title="My CV"
/>
</div>
<div className="status">
<Clock className="clock" />
</div>
</div>
</div>
</div>
);
}
And on click i want to get displayed in desktop-app-grid like this:
<div
className="desktop-app-grid"
>
<documentReader />
</div>
icon.js (code isn't complete)
class TaskbarAppIcon extends React.Component {
constructor() {
super();
this.state = {
clicked: false
};
this.handleClick = this.handleClick.bind(this);
}
handleClick = () => {
const icon = document.querySelector("img");
icon.classList.toggle("icon-active");
setTimeout(() => {
icon.classList.toggle("icon-active");
}, 200);
this.setState({
clicked: true
});
}
render(){
const classes = this.props.appName + "Icon icon";
return (
<div className={classes} onClick={this.handleClick}>
<img src={this.props.icon} alt={this.props.appName} title={this.props.title} className="icon-image"></img>
<div className="isActive"></div>
</div>
);
}
}
export default TaskbarAppIcon;
is there any function that works like innerHTML, but isn't a dangerouslyInnerHTML?

what you need to do is move your handleClick and clicked state to the parent component where you rendering TaskbarAppIcon. Being more specific where you have this code:
<div className="desktop">
<div className="desktop-app-grid">
</div>
<div className="taskbar">
<div className="taskbar-content">
<div className="apps">
<TaskbarAppIcon
appName="documentReader"
icon={icon}
title="My CV"
/>
</div>
<div className="status">
<Clock className="clock" />
</div>
</div>
</div>
</div>
So for example, the above code is in you App component, so you need to let it like this:
class App extends React.Component {
constructor() {
super();
this.state = {
clicked: false,
};
this.handleClick = this.handleClick.bind(this);
}
handleClick = () => {
const icon = document.querySelector("img");
icon.classList.toggle("icon-active");
setTimeout(() => {
icon.classList.toggle("icon-active");
}, 200);
this.setState({
clicked: !this.state.clicked,
});
};
render() {
return (
<div className="desktop">
<div className="desktop-app-grid">
// here's the trick, if your clicked state is TRUE it will show <documentReader />
{this.state.clicked && <documentReader />}
</div>
<div className="taskbar">
<div className="taskbar-content">
<div className="apps">
<TaskbarAppIcon
// Here you are specifying that TaskbarAppIcon has a prop handleClick and its a function
handleClick={this.handleClick}
appName="documentReader"
icon={icon}
title="My CV"
/>
</div>
</div>
</div>
</div>
);
}
}
And in your TaskbarAppIcon component you just need to change
<div className={classes} onClick={this.handleClick}>
to
<div className={classes} onClick={this.props.handleClick}>

Related

React issue with show / hiding elements

This project is using React.
The goal is that when the maximize icon is clicked on the the Editor component, the Preview component will be hidden. When the maximize icon is clicked on the Preview component, the Editor component will be hidden.
The problem is, when I click the maximize icon on the Editor component, the only thing that displays is the text "not found." But the Preview maximize icon works when clicked.
I logged state to the console so I know that the state is updating when the editor button is clicked, but I can't figure out what is wrong with the way I am rendering the Editor element.
Codepen link: https://codepen.io/Jamece/pen/Exbmxmv
Thank you for any help you can provide.
import * as marked from "https://cdn.skypack.dev/marked#4.0.12";
class Application extends React.Component {
constructor(props) {
super(props);
this.state = {
editorOnly: false,
previewOnly: false,
inputValue: "",
outputValue: ""
};
this.handleChange = this.handleChange.bind(this);
this.editorChange = this.editorChange.bind(this);
this.previewChange = this.previewChange.bind(this);
}
handleChange(event) {
this.setState({
inputValue: event.target.value
});
}
//changes view to editorOnly when editor maximize button is clicked then back to full view when clicked again
editorChange() {
this.setState((state) => {
if (state.editorOnly === false) {
return { editorOnly: true };
} else {
return { editorOnly: false };
}
});
}
//changes view to previewOnly when preview maximize button is clicked then back to full view when clicked again
previewChange() {
this.setState((state) => {
if (state.previewOnly === false) {
return { previewOnly: true };
} else {
return { previewOnly: false };
}
});
}
render() {
console.log(this.state);
if (this.state.editorOnly === false && this.state.previewOnly === false) {
return (
<div className="container-fluid px-0">
<div className="d-flex flex-column main">
<Editor editorChange={this.editorChange}
handleChange={this.handleChange}/>
<Preview previewChange={this.previewChange} />
</div>
</div>
);
} else if (
this.state.editorOnly === true &&
this.state.previewOnly === false
) {
return (
<div className="container-fluid px-0">
<div className="d-flex flex-column main">
<Editor editorChange={this.editorChange}
handleChange={this.handleChange}/>
</div>
</div>
);
} else if (
this.state.editorOnly === false &&
this.state.previewOnly === true
) {
return (
<div className="container-fluid px-0">
<div className="d-flex flex-column main">
<Preview previewChange={this.previewChange} />
</div>
</div>
);
}
else {
return(
<div></div>
)
}
}
}
class Editor extends React.Component {
constructor(props) {
super(props);
}
render() {
return (
<div className="d-flex justify-content-center">
<form>
<div className="boxes">
<div className="d-flex align-items-center label-bar">
<div className="leftcon">
<i className="fa-solid fa-book"></i>
</div>
<div className="headings">Editor</div>
<div className="rightcon">
<button className="btn" onClick={this.props.editorChange}>
<i className="fa-solid fa-maximize"></i>
</button>
</div>
</div>
<textarea
value={this.props.inputValue}
onChange={this.props.handleChange}
></textarea>
</div>
</form>
</div>
);
}
}
class Preview extends React.Component {
constructor(props) {
super(props);
}
render() {
return (
<div>
<div className="d-flex justify-content-center">
<form>
<div className="boxes">
<div className="d-flex align-items-center label-bar">
<div className="leftcon">
<i className="fa-solid fa-book"></i>
</div>
<div className="headings">Preview</div>
<div className="rightcon">
<button className="btn" onClick={this.props.previewChange}>
<i className="fa-solid fa-maximize"></i>
</button>
</div>
</div>
<div className="preview">
<br /> <br /> <br /> <br /> <br /> <br /> <br /> <br />
</div>
</div>
</form>
</div>
</div>
);
}
}
ReactDOM.render(<Application />, document.getElementById("app"));
A button element inside a form element by default has type="submit".
Hence, when you click the maximize button it tries to submit the form, making an http request.
This is not what you want here so you should set type="button" on your buttons. This way they will not trigger a form submission on click.
The same thing happens on your Preview component, but note that in the console you get the following message:
Form submission canceled because the form is not connected
I believe this is because the way you order the elements in the different states causes React to recreate the preview window in the DOM. If you switch Editor and Preview around in the state where both are visible then Editor works fine and Preview is broken.

React state change not causing re-render

I am trying to toggle the visibility of a div when clicking a seperate div. The problem is it sets the div invisible on the first click and only if it is visible to begin with. After that it just stays invisible and will not update. The state is still being toggled in the console however.
import React, { Component } from 'react';
import './App.css';
class App extends Component {
constructor(){
super()
this.state = {
vis: '0'
}
}
toghide=()=>{
console.log("toggle login", this.state.vis)
if(this.state.vis === "hidden"){
console.log('showing')
this.setState((state, props)=>({vis:'0'}))
} else {
console.log('hiding')
this.setState((state, props)=>({vis:'hidden'}))
}
}
render() {
const styles = {
visibility: this.state.vis
}
return (
<div className="App">
<div className="salebar"><a className="salebar sale"
href="login">Click here!</a></div>
<div className="navbar">
<div className="nav"><div className="nnav">JMZ</div></div>
<div className="nav2"><div className="nnav2">PRODUCTS</div></div>
<div className="loginContainer"><div className="login" onClick={this.toghide}>LOGIN/SIGN UP</div></div>
</div>
<div className="login-container">
<div className="lognester">
<div style={styles} className="login-tab">
<input className="user" type="text" placeholder="Username"/>
<input className="password" type="password" placeholder="Password"/>
<button className="user">Login</button>
Sign in or <a className="register-link" href="register">register</a> a new account.
</div>
</div>
</div>
<div className="intro-pics"></div>
<div className="content"></div>
<audio preload loop controls autoPlay className="audio">
<source src="https://memefly.me/i/toValhalla.mp3"/>
Your browser does not support the audio element.
</audio>
</div>
);
}
}
export default App;
Try this:
class App extends Component {
constructor() {
super();
this.state = {
vis: true
};
}
toghide = () => {
this.setState({ vis: !this.state.vis });
};
render() {
return (
<div className="App">
<div className="salebar">
<a className="salebar sale" href="login">
Click here
</a>
</div>
<div className="navbar">
<div className="nav">
<div className="nnav">JMZ</div>
</div>
<div className="nav2">
<div className="nnav2">PRODUCTS</div>
</div>
<div className="loginContainer">
<div className="login" onClick={this.toghide}>
LOGIN/SIGN UP
</div>
</div>
</div>
<div className="login-container">
<div className="lognester">
{this.state.vis ? (
<div className="login-tab">
<input className="user" type="text" placeholder="Username" />
<input
className="password"
type="password"
placeholder="Password"
/>
<button className="user">Login</button>
Sign in or{' '}
<a className="register-link" href="register">
register
</a>{' '}
a new account.
</div>
) : (
''
)}
</div>
</div>
<div className="intro-pics" />
<div className="content" />
</div>
);
}
}
export default App;
This is the demo: https://codesandbox.io/s/72zzk2xr70
Two things are wrong with your code
It should be visibility:visible not visibility: 0. So change that.
Never ever ever ever... set state in your render function, really really bad practice.
1 ) You can declare your togHide method above render such as
toghide = () => {
//your code
}
render(){...}
2) You may handle visibility condition better if you just use true/false boolean logic on your vis state. This can be as :
constructor(){
super()
this.state = {
vis: true
}
}
toghide = () => {
if(this.state.vis){
this.setState({
vis : false
})}
else{
this.setState({
vis : true
})}
3) In toghide method, you can use the code for setState I've used above. You don't have to pass props if you don't use any, and don't need to use return in setState.

Update component with data from parent in React

In my react app I have this child component that inherits data from its parent. However, it does not update the page with new data from the child component when a relevant anchor link is clicked.
Here's my build - https://suite-search-lk.surge.sh/result/369523
From the link above if you click on a suggested card h1 element it just updates the URL with the id but does not update the page with the relevant card data from that id.
Any idea how I can fix this? Do I have to force the component to re-update?
Parent component (Card Wrapper)
class CardWrapper extends React.Component {
constructor(props) {
super(props);
this.state = {
stories: []
};
}
componentDidMount() {
axios
.get(API)
// .then(response => console.log(response))
// get our stories array, check it and then change state to contain our stories
.then(data => {
let stories;
if (data.data.stories && data.data.stories) {
if (Array.isArray(data.data.stories)) {
stories = data.data.stories;
} else {
stories = [data.data.stories];
}
} else {
stories = [];
}
this.setState({
stories: stories
});
});
}
render() {
return (
<CardWrapperDiv>
<div className="headingWrapper">
<div className="heading"> Suggested for you</div>
</div>
<Cards>
{this.state.stories.map(story => {
return (
<Card
title={story.content.title}
img={story.content.img}
description={story.content.description}
deadline={story.content.deadline_date}
tags={story.content.tags}
key={story.id}
id={story.id}
/>
);
})}
</Cards>
</CardWrapperDiv>
);
}
}
export default CardWrapper;
Child component
class Card extends React.Component {
render() {
return (
<CardDiv>
<div className="cardbox">
<div className="cardDetails">
<div className="headlineText">
<Link to={`/result/${this.props.id}`}> {this.props.title} </Link>
</div>
<div className="headlineSub">Colombo, Sri Lanka</div>
<div className="headlineDes">{this.props.description}</div>
<div className="textRemain">
{" "}
Deadline date: {this.props.deadline}
</div>
<div className="buttonRow">
<button className="downloadBtn">Download</button>
<button className="viewBtn">View</button>
</div>
</div>
<div className="cardimgwrapper">
<div className="cardimg">
<img src={this.props.img} alt="some title" />
</div>
</div>
</div>
</CardDiv>
);
}
}
export default Card;
Sorry it seems I have figured this out using the following post - Can you force a React component to rerender without calling setState?
Although I'm not exactly sure if it's the best way to go about it.
Essentially I used an OnClick listener to run a function and forces a re-render of the entire component.
Hope this can help someone else :)
class Card extends React.Component {
handleButtonClick() {
this.forceUpdate();
}
render() {
return (
<CardDiv>
<div className="cardbox">
<div className="cardDetails">
<div className="headlineText">
<Link to={`/result/${this.props.id}`} onClick={this.handleButtonClick}> {this.props.title} </Link>
</div>
<div className="headlineSub">Colombo, Sri Lanka</div>
<div className="headlineDes">{this.props.description}</div>
<div className="textRemain">
{" "}
Deadline date: {this.props.deadline}
</div>
<div className="buttonRow">
<button className="downloadBtn">Download</button>
<button className="viewBtn">View</button>
</div>
</div>
<div className="cardimgwrapper">
<div className="cardimg">
<img src={this.props.img} alt="some title" />
</div>
</div>
</div>
</CardDiv>
);
}
}
export default Card;
U have to use ur child component as a pure component. PureComponent Update when ur props change.
class Card extends React.PureComponent {
handleButtonClick() {
this.forceUpdate();
}
render() {
return (
<CardDiv>
.....
.....
</CardDiv>
);
}
}
export default Card;

Changing multiple props const to class

I want to convert functional component in React to class based component, because I want to make use of state property.
Currently I have this component which has 2 props.
const VideoListItem = ({video, onVideoSelect}) => {
const imageUrl=video.snippet.thumbnails.default.url;
return (
<li onClick={() => onVideoSelect(video)} className="list-group-item">
<div className="video-list media">
<div className="media-left">
<img className="media-object" src={imageUrl} />
</div>
<div className="media-body">
<div className="media-heading">{video.snippet.title}</div>
</div>
</div>
</li>
)
}
I tried to convert it to class and ended up with this:
class VideoListItem extends React.Component {
render() {
const {video} = this.props.video
const imageUrl=video.snippet.thumbnails.default.url;
const{onVideoSelect} =this.props.onVideoSelect
return (
<li onClick={() => onVideoSelect(video)} className="list-group-item">
<div className="video-list media">
<div className="media-left">
<img className="media-object" src={imageUrl} />
</div>
<div className="media-body">
<div className="media-heading">{video.snippet.title}</div>
</div>
</div>
</li>
)
}
}
However It does not work, I get errors. I guess it has something to do with 2 props being in the component. Anyone has idea how can I change the first code to be a class component?
Your destructuring is a bit off:
const { video } = this.props.video;
const{ onVideoSelect } = this.props.onVideoSelect;
should be something like:
const { video } = this.props;
const{ onVideoSelect } = this.props;
and you can combine these if you want:
const { video, onVideoSelect } = this.props;

How to show loader in reactjs and meteor?

I have a page where 3 recipes are listed along with more button. When more button is clicked more 3 recipes are listed. What i am trying to do is before listing more 3 recipes i want to show a spinner/loader icon but i could only change the text of button. How can i show loader icon as soon as more button is clicked and before those additional 3 recipes are listed. I am using meteorjs and reactjs.
my code for this is
export default class Home extends Component {
constructor(){
super();
this.state = { limit:3 , loading:false }
this.addMore = this.addMore.bind(this);
}
getMeteorData(){
let data = {};
data.recipes = [];
data.recipes = Recipes.find({},{sort:{createdAt:-1}}).fetch();
let recipeHandle = Meteor.subscribe('recipelist',this.state.limit);
if(recipeHandle.ready()){
data.recipes = Recipes.find({},{sort:{createdAt:-1},limit:this.state.limit}).fetch();
}
return data;
}
addMore(){
this.setState({
limit:this.state.limit + 3, loading: true }, () => {
this.setTimeout(()=>{
this.setState({loading:false});
},2000);
});
}
render() {
console.log('this.data.recipes',this.data.recipes);
let recipes = _.map(this.data.recipes,(recipe) => {
return <RecipeList key={recipe._id} recipe={recipe} loading={this.state.loading} />
});
return (
<div className="row">
<div className="intro blink z-depth-1">
<div className="row">
<div className="col l7">
<h1 className="heading flow-text blink">Sell your Recipe</h1>
</div>
</div>
</div>
<div className="row">
<div className="col s12">
{recipes}
</div>
</div>
<button onClick={this.addMore} type="button" className="btn coral more">More</button>
</div>
);
}
}
ReactMixin(Home.prototype, ReactMeteorData);
You could remove the loading state, and just compute the loading state from the data: {this.state.limit !== this.data.recipes.length && <img src="path_to_loader.gif" />}
I am not sure where you want to show the loader, but for example you could do:
render() {
console.log('this.data.recipes',this.data.recipes);
let recipes = _.map(this.data.recipes,(recipe) => {
return <RecipeList key={recipe._id} recipe={recipe} loading={this.state.loading} />
});
return (
<div className="row">
<div className="intro blink z-depth-1">
<div className="row">
<div className="col l7">
<h1 className="heading flow-text blink">Sell your Recipe</h1>
</div>
</div>
</div>
<div className="row">
<div className="col s12">
{recipes}
</div>
</div>
{this.state.limit !== this.data.recipes.length && <img src="path_to_loader.gif" />}
<button onClick={this.addMore} type="button" className="btn coral more">More</button>
</div>
);
}

Categories