reactJs useRef to add or Remove className - reactjs

How to Add className or Remove ClassName using useRef
code follows
const refs = useRef("");
const clicka =()=>{ ref.current.classList.add('correct') }
<div onClick={()=>{clicka()}} refs={ref} className="js-choose-answer"><div>a</div>{user.opt1}</div></div>
i can Access className Value ref.current.className but unable to add
code
import React, { useState, useEffect,useRef} from 'react';
const Slugg = ({user}) => {
//onClick to set className "js-choose-answer correct"
return (
<div>
<div className="__options">
<div onClick={()=>{clicka(user._id)}} ref={ref} className="js-choose-answer"><div>a</div><{user.opt1} </div></div>
</div>
<div className="__options">
<div onClick={()=>{clicka(user._id)}} ref={ref} className="js-choose-answer"><div>a</div><{user.opt1} </div></div>
</div>
</div>
)
}

Try this using useState. Set a boolean corresponding to user id which rerenders the elements with classname correct
const [status, setStatus] = useState({});
const clicka =(userId)=>{
setStatus(prevStatus=>{
return {...prevStatus, [userId]: true}
})
}
<div onClick={()=>{clicka(user._id)}} className={`js-choose-answer ${status[user._id] ? 'correct': ''}`}><
<div>a</div><{user.opt1} </div></div>
</div>

I usually do this and it works
const currentElement = useRef(null)
const switchClassHandler = () => {
currentElement.current.classList.add('correct')
currentElement.current.classList.remove('error')
}
return (
<React.Fragment>
<div ref={currentElement} onClick={switchClassHandler} className={'global error'}>
hello
</div>
</React.Fragment>
)

Related

How can we create a editable `<code>` tag on fly and add different attributes to that

On click on Code button, how can we create a editable <code> tag on fly and add different attributes in react web app ?
Or may be an editable field display as code tag ? Could someone please advise here ?
import React, { useState } from 'react';
import { useNavigate } from "react-router-dom";
const Admin = () => {
const [createCode, setCreateCode] = useState("");
const navigate = useNavigate();
const createCodeSection = () => {
const newElement = React.createElement('code', {key: 'ele'+ new Date().getTime(), className:'codehighlight'}, `--sample code to enter-- `,);
setCreateCode(createCode => [...createCode, newElement]);
}
const handleLogout = () => {
localStorage.removeItem('loginEmail');
navigate("/login");
};
return (
<div id="App">
<div className='adminSection'>
<div className='row'>
<div className="logout">
<img src="/images/logout.png" alt="Logout" onClick={handleLogout}></img>
</div>
<div className='createBlogSection'>
<div className='row'>
<button onClick={createCodeSection}>Code</button>
<button>Image</button>
<button>Code</button>
</div> <br></br>
<textarea>
{createCode}
</textarea>
</div>
</div>
</div>
</div>
)
}
export default Admin;
css:
.codehighlight{
background-color: #353232;
color: #fff;
}

React question : how to pass an id from a component to another on click?

I need your help with an app that I am building. It has a forum page and I have some issues with the forum and post components.
I am trying to pass the id of the post that the user clicked on, with history.push so on the post page the id in the url that I try to get with useParams, has the value of the one I send with history.push. The purpose is for some queries I do so I show the post with its comments.
For now the layout isn’t great because I have to make this feature work.
I do not understand why it doesn’t. My console.logs show null or undefined which make no sense to me.
Thank you if you can help me with this.
Here you have two routes present in the App component. It is important for the last route, the Post one were I use :id so I can get it with useParams.
{/* Route for Trainings Wakeup Rebirth */}
<Route path='#forum' exact component={TrainingsWakeupRebirth} />
<Route path='#forum/:id' exact component={Post} />
Here you have the entire code of the Forum page. Like that you can see how I use history.push to send the value.id of the post to the Post component and the way the component itself is built.
import React, { useState, useEffect, useRef } from 'react';
import { useHistory } from 'react-router-dom';
import ReactPaginate from "react-paginate";
import Post from "../Post/Post";
import './TrainingsWakeupRebirth.scss';
import axios from "axios";
const TrainingsWakeupRebirth = (props) => {
let history = useHistory();
// const forumSectionRef = useRef();
// const postSectionRef = useRef();
const forumSection = document.getElementById('forum-block-wrapper');
const postSection = document.getElementById('post-section');
const showPost = () => {
if (forumSection.style.display === 'block') {
return forumSection.style.display = 'none',
postSection.style.display = 'block';
} else {
return forumSection.style.display = 'block',
postSection.style.display = 'none';
}
}
const [listOfPosts, setListsOfPosts] = useState([]);
const [pageNumber, setPageNumber] = useState(0);
const postsPerPage = 2;
const pagesVisited = pageNumber * postsPerPage;
const displayPosts = listOfPosts.slice(pagesVisited, pagesVisited + postsPerPage).map((value, key) => {
const forParams = () => {
return history.push(`#forum/${value.id}`);
}
const executeAll = () => {
forParams();
showPost();
if(forParams()) {
let id = value.id;
return id;
}
}
return (
<div key={key}>
<div className="topic-row" onClick={() => {executeAll()}}>
<div className="topic-title">{value.title}</div>
<div className="topic-image">
<img src={value.image} alt=""></img>
</div>
<div className="topic-message">{value.postText}</div>
</div>
</div>
);
});
const pageCount = Math.ceil(listOfPosts.length / postsPerPage);
const changePage = ({selected}) => {
setPageNumber(selected);
};
useEffect(() => {
axios.get("http://localhost:3001/posts").then((response) => {
setListsOfPosts(response.data);
});
}, []);
console.log(listOfPosts);
return (
<div className="forum" id="forum">
<div className="forum-section-wrapper page" id="forum-wrapper">
<div className="fluid-grid">
<div className="row">
<div className="col-12">
<div className="title">
<h1><span className="first-title-part">Krishna</span><span className="second-title-part">Hara</span></h1>
</div>
<div className="quote">
<span className="quote-left">FORUM</span><span className="quote-right">Eco Village</span>
</div>
</div>
</div>
<div className="row">
<div className="col-12">
<div className="forum-block-wrapper" id="forum-block-wrapper">
{displayPosts}
<ReactPaginate
previousLabel={"Previous"}
nextLabel={"Next"}
pageCount={pageCount}
onPageChange={changePage}
containerClassName={"paginationBttns"}
previousLinkClassName={"previousBttn"}
nextLinkClassName={"nextBttn"}
activeClassName={"paginationActive"}
/>
</div>
</div>
</div>
</div>
</div>
<div className="post-section" id="post-section">
<div className="fluid-grid">
<div className="row">
<div className="col-12">
<Post />
</div>
</div>
</div>
</div>
</div>
)
};
export default TrainingsWakeupRebirth;
Here is some code from the Post component, so you can see the code that should work but doesn't. Also the console.log(id)
import React, { useEffect, useState } from "react";
import { useParams } from "react-router-dom";
import axios from "axios";
const Post = (props) => {
let { id } = useParams();
const [postObject, setPostObject] = useState({});
const [comments, setComments] = useState([]);
const [newComment, setNewComment] = useState("");
console.log(id);
useEffect(() => {
axios.get(`http://localhost:3001/posts/byId/${id}`).then((response) => {
console.log(response);
setPostObject(response.data);
});
axios.get(`http://localhost:3001/comments/${id}`).then((response) => {
setComments(response.data);
});
}, [id]);
const addComment = () => {
axios.post("http://localhost:3001/comments", {
commentBody: newComment,
Postid: id,
})
.then((response) => {
const commentToAdd = { commentBody: newComment };
setComments([...comments, commentToAdd]);
setNewComment("");
});
};
console.log(postObject);
return (
<div className="post-section-wrapper">
{/* <div>
<div className="title">
{postObject.title}
</div>
<div className="image">
<img src={postObject.image}></img>
</div>
<div className="message">
{postObject.postText}
</div>
</div> */}
<div className="comments-wrapper">
<div className="">
<input
type="text"
placeholder="Comment..."
autoComplete="off"
value={newComment}
onChange={(event) => {
setNewComment(event.target.value);
}}
/>
<button onClick={addComment}> Add Comment</button>
</div>
<div className="comments-row">
{comments.map((comment) =>
(
<div key={comment.id} className="comment">
{comment.commentBody}
</div>
)
)}
</div>
</div>
</div>
);
}
export default Post;
Thank you very very much!!!
#DrewReese and #JoelHager Thank you so much for checking my code and for your advice. In the meantime I found out that we can pass to a component, aside from the pathname, other values with history.push that we retrieve by using useLocation in the component that we want to. I will answer my own question and add the code.
Here is my Forum component, I prefer adding the entire code so everything is clear. In forParams you will see how I pass the value that I need with useHistory and the attribute state and detail.
import React, { useState, useEffect, useRef } from 'react';
import { useHistory } from 'react-router-dom';
import ReactPaginate from 'react-paginate';
import Post from '../Post/Post';
import './TrainingsWakeupRebirth.scss';
import axios from 'axios';
const TrainingsWakeupRebirth = (props) => {
let history = useHistory();
// const forumSectionRef = useRef();
// const postSectionRef = useRef();
const forumSection = document.getElementById('forum-block-wrapper');
const postSection = document.getElementById('post-section');
const showPost = () => {
if (forumSection.style.display === 'block') {
return forumSection.style.display = 'none',
postSection.style.display = 'block';
} else {
return forumSection.style.display = 'block',
postSection.style.display = 'none';
}
}
const [listOfPosts, setListsOfPosts] = useState([]);
const [pageNumber, setPageNumber] = useState(0);
const postsPerPage = 2;
const pagesVisited = pageNumber * postsPerPage;
const displayPosts = listOfPosts.slice(pagesVisited, pagesVisited + postsPerPage).map((value, key) => {
const forParams = () => {
history.push(
{
pathname: `#forum#${value.id}`,
state: { detail: value.id }
}
);
}
const executeAll = () => {
forParams();
showPost();
}
return (
<div key={key} onClick={() => {executeAll()}}>
<div className="topic-row">
<div className="topic-title">{value.title}</div>
<div className="topic-image">
<img src={value.image} alt=""></img>
</div>
<div className="topic-message">{value.postText}</div>
</div>
</div>
);
});
const pageCount = Math.ceil(listOfPosts.length / postsPerPage);
const changePage = ({selected}) => {
setPageNumber(selected);
};
useEffect(() => {
axios.get("http://localhost:3001/posts").then((response) => {
setListsOfPosts(response.data);
});
}, []);
console.log(listOfPosts);
return (
<div className="forum" id="forum">
<div className="forum-section-wrapper page" id="forum-wrapper">
<div className="fluid-grid">
<div className="row">
<div className="col-12">
<div className="title">
<h1><span className="first-title-part">Krishna</span><span className="second-title-part">Hara</span></h1>
</div>
<div className="quote">
<span className="quote-left">FORUM</span><span className="quote-right">Eco Village</span>
</div>
</div>
</div>
<div className="row">
<div className="col-12">
<div className="forum-block-wrapper" id="forum-block-wrapper">
{displayPosts}
<ReactPaginate
previousLabel={"Previous"}
nextLabel={"Next"}
pageCount={pageCount}
onPageChange={changePage}
containerClassName={"paginationBttns"}
previousLinkClassName={"previousBttn"}
nextLinkClassName={"nextBttn"}
activeClassName={"paginationActive"}
/>
</div>
</div>
</div>
</div>
</div>
<div className="post-section" id="post-section">
<div className="fluid-grid">
<div className="row">
<div className="col-12">
<Post />
</div>
</div>
</div>
</div>
</div>
)
};
export default TrainingsWakeupRebirth;
In the Post component with useLocation and useEffect I get location.state.detail which is the id of the Post, that with useState I set to the constant postId.
import React, { useEffect, useState } from "react";
import { useParams, useHistory, useLocation } from "react-router-dom";
import axios from "axios";
import './Post.scss';
const Post = (props) => {
// let { id } = useParams();
const location = useLocation();
const [postId, setPostId] = useState();
useEffect(() => {
console.log(location.pathname); // result: '#id'
if(location.state) {
console.log(location.state.detail); // result: postId
setPostId(location.state.detail);
}
}, [location]);
const [postObject, setPostObject] = useState({});
const [comments, setComments] = useState([]);
const [newComment, setNewComment] = useState("");
// console.log(id);
useEffect(() => {
axios.get(`http://localhost:3001/posts/byId/${postId}`).then((response) => {
console.log(response.data);
setPostObject(response.data);
});
axios.get(`http://localhost:3001/comments/${postId}`).then((response) => {
setComments(response.data);
});
}, [postId]);
const addComment = () => {
axios.post("http://localhost:3001/comments", {
commentBody: newComment,
Postid: postId,
})
.then((response) => {
const commentToAdd = { commentBody: newComment };
setComments([...comments, commentToAdd]);
setNewComment("");
});
};
if(postObject !== null) {
console.log(postObject);
}
return (
<div className="post-section-wrapper">
{postObject !== null
?
<div className="posts-wrapper">
<div className="title">
{postObject.title}
</div>
<div className="image">
<img src={postObject.image}></img>
</div>
<div className="message">
{postObject.postText}
</div>
</div>
:
null
}
<div className="comments-wrapper">
<div className="">
<input
type="text"
placeholder="Comment..."
autoComplete="off"
value={newComment}
onChange={(event) => {
setNewComment(event.target.value);
}}
/>
<button onClick={addComment}> Add Comment</button>
</div>
<div className="comments-row">
{comments.map((comment) =>
(
<div key={comment.id} className="comment">
{comment.commentBody}
</div>
)
)}
</div>
</div>
</div>
);
}
export default Post;

Cannot read property 'map' of undefined in react while passing through props

I am building simple react application it showing map is undefine please resolve this error it might help a lot
child code
const classes = useStyles()
const {qnsObject,answersList} = props.value
console.log(qnsObject,answersList)
return (
qnsObject.map((content,index) =>{
let count = content.tags.split(',')
return (
<div className = {classes.homeRecentQns} >
<div className ={classes.homeRecentQnsParent}>
<div className = {classes.avatar_parent}>
<div className ={classes.avatar}>
<Avatar alt='tfds' src ={content.profile_img} className
= {classes.small}>{content.firstName[0].toUpperCase()}</Avatar>
</div>
<div className ={classes.voted_parent}>
<ArrowDropUpTwoToneIcon className =
{classes.voted_up}/>
<p>125</p>
<ArrowDropDownTwoToneIcon className =
{classes.voted_down}/>
</div>
</div>
<div className ={classes.recentQns_parent}>
<div className = {classes.recentQns_tags_parent}>
<p className = {classes.recentQns_name}>
{content.firstName} {content.lastName}</p>
<p className = {classes.recentQns_occupation}>
{content.currentWorking}</p>
<p className = {classes.recentQns_askedIn}><b
className = {classes.recentQns_askedIn_bold}>Asked in:
</b>{content.posted_date}</p>
</div>
<div className ={classes.recentQns_desc}>
<p className ={classes.recentQns_title}>
{content.qnsTitle}</p>
<p className ={classes.recentQns_answers}>
{ReactHtmlParser(content.Question_body)}
</p>
</div>
<div className ={classes.recentQns_topic_tags}>
{content.tags.split(',').map(chip =>{
return <> <Chip label={chip} variant="filled"
color="primary" size="small" icon=
{<LocalOfferTwoToneIcon />} /></>
})}
</div>
<div className ={classes.recentQns_views_parent}>
<div className = {classes.popular_desc_view}>
<QuestionAnswerIcon className =
{classes.views_icon}/>
<div className = {classes.p}>
{answersList.length} Answers</div>
</div>
<div className = {classes.popular_desc_view}>
<VisibilityIcon className =
{classes.views_icon}/>
<div className = {classes.p}>5 views</div>
</div>
</div>
</div>
</div>
</div>
)
})
)
parent code
const Auth = useContext(Authapi)
const [body,setBody] = useState("")
const [open, setOpen] = React.useState(false);
const [dataQns,setDataqns] = useState([])
const [closeAns, setAns] = React.useState(false);
let href = window.location.href.split('/')
console.log(dataQns)
const classes = useStyles()
useEffect(() =>{
const get = async () =>{
const data = await fetch('/getAnswers/'+href[href.length -1])
const dataItems = await data.json()
console.log(dataItems)
setDataqns(dataItems)
}
get()
},[dataQns])
this props I passing
<ViewPostComponent value = {dataQns}/>
how to get update when new data is ready to render using hooks please answer to this question
how to update map function when new data getting from server
map is undefined means that you have not passed any data to the map() function
You can use content loading before api call
{!!dataQns ? (<ViewPostComponent value = {dataQns}/> ) : (<SomeLoadingSvgAnimationComponent>) }
Probably you are mapping an empty array or a variable that is not an array.
You can check the length before mapping.
{
variable.length > 0 && variable.map((e) => your code )
}
Update
Instead of using just a variable, you need to use React State.
When data is loaded, set the data into the state and everything will work.
{qnsObject && qnsObject.map((content,index)........}
Try this while mapping. Mapping will occur only when qnsObject is an array else it will return null.

Trying to change React Style attribute by changing state hook

Transform is not updating the style component below. I have console logged the state to ensure that it is changing and it was, just not the style component (it kept the color red).
import React, {useState} from 'react';
const Carousel = () => {
let [selectedIndex, setSelectedIndex] = useState(0)
const [cellCount,] = useState(9);
let [transform, setTransform] = useState({color: 'red'});
const prevButton = () => {
setSelectedIndex(selectedIndex-1);
setTransform({color: 'green !important'})
console.log(selectedIndex)
console.log(transform)
};
const nextButton = () => {
setSelectedIndex(selectedIndex+1);
setTransform({color: 'red !important'})
console.log(transform)
}
return (
<>
<div className="scene">
<div style={transform} className="carousel">
<div className="carousel__cell">1</div>
<div className="carousel__cell">2</div>
<div className="carousel__cell">3</div>
<div className="carousel__cell">4</div>
<div className="carousel__cell">5</div>
<div className="carousel__cell">6</div>
<div className="carousel__cell">7</div>
<div className="carousel__cell">8</div>
<div className="carousel__cell">9</div>
</div>
</div>
<button onClick={prevButton}>
Previous
</button>
<button onClick={nextButton}>
Next
</button>
</>
)
}
React inline style doesn't know the !important property. There is usually always a way to avoid using it, and it is better to do so.
If you just don't avoid using !important, it will work here.
If you have to set it, this would work:
import React, { useState } from 'react';
const Carousel = () => {
let [selectedIndex, setSelectedIndex] = useState(0);
let [transform, setTransform] = useState({ color: 'red' });
const prevButton = () => {
setSelectedIndex(selectedIndex - 1);
setTransform({ ...{ color: 'green' } });
// rotateCarousel();
console.log(selectedIndex);
console.log(transform);
};
const nextButton = () => {
setSelectedIndex(selectedIndex + 1);
setTransform({ ...{ color: 'red' } });
console.log(transform);
// rotateCarousel();
};
return (
<>
<div className="scene">
<div
ref={el => {
if (el) {
el.style.setProperty('color', transform.color, 'important');
}
}}
className="carousel"
>
<div className="carousel__cell">1</div>
{transform.color}
<div className="carousel__cell">2</div>
<div className="carousel__cell">3</div>
<div className="carousel__cell">4</div>
<div className="carousel__cell">5</div>
<div className="carousel__cell">6</div>
<div className="carousel__cell">7</div>
<div className="carousel__cell">8</div>
<div className="carousel__cell">9</div>
</div>
</div>
<button onClick={prevButton}>Previous</button>
<button onClick={nextButton}>Next</button>
{transform.color}
</>
);
};
export default Carousel;

Building Dropdown component

I'm having a problem building a dropdown component. In the function to get the selected item I'm having this error :
Too many re-renders. React limits the number of renders to prevent an
infinite loop.
The code for the component :
import React, { useState } from 'react';
import PropTypes from 'prop-types';
import '../../../App.css'
function Dropdown({ items }) {
//const [list, setList] = useState(items);
const [selectedItem, setSelectedItem] = useState(items[0]);
const [showItems, setShowItem] = useState(false);
const [setExpand, setExpandState] = useState("");
function toggleDropdown() {
setExpandState(setExpand === "" ? "dropdown-expanded dropdown-expanded-down" : "");
setShowItem(showItems === false ? true : false);
};
const Changed = (item) => {
setShowItem(false);
setSelectedItem(item);
}
return (
<div data-dropdown="" className={`dropdown-container dropdown ${setExpand}`} onClick={toggleDropdown} >
<div className="dropdown-display">
<div className="dropdown-display-content" >
<span data-expression="" class="OSFillParent"> {selectedItem.value} </span>
</div>
</div>
<div className="dropdown-list" style={{ display: showItems ? 'block' : 'none' }} >
<div className="scrollable-list scrollable-list-with-scroll">
{items.map(item =>
<div className="dropdown-popup-row" key={item.id} onClick={Changed(item)} > {item.value} </div>
)}
</div>
</div>
</div>
);
}
Dropdown.propTypes = {
items: PropTypes.array,
}
export default Dropdown;
The problem is on here onClick={Changed(item)}
You are calling this on each render, and it's modifying the state every render, so it gets called again recursively.
You can solve it by doing:
<div className="dropdown-popup-row"
key={item.id}
onClick={() => Changed(item)}>
{item.value}
</div>

Resources