making reusable component in reactjs - reactjs

I have the following code, want to remove the repeated content code inside <ReactCSSTransitionGroup to a separate file - does not look straight forward to pass props to and fro from child/parent, how do I do it? is it do-able?
<div className="container">
<ReactCSSTransitionGroup transitionName="example" transitionEnterTimeout={500} transitionLeaveTimeout={300}>
<span key={this.state.showChild1} className="plus_icon">
<a onClick={() => this.onClick('child1')}>
<Img className={this.state.showChild1 ? 'plus_icon' : 'minus_icon'} />
</a>
</span>
</ReactCSSTransitionGroup>
{this.state.child1 ? <Child1-New /> : <div onClick={() => this.onClick('child1')}><Child1 /></div>}
</div>
<div className="container">
<ReactCSSTransitionGroup transitionName="example" transitionEnterTimeout={500} transitionLeaveTimeout={300}>
<span key={this.state.showChild2} className="plus_arrow">
<a onClick={() => this.onClick('child2')}>
<img className={this.state.child2 ? 'plus_icon' : 'minus_icon'} />
</a>
</span>
</ReactCSSTransitionGroup>
{this.state.child2 ? <Child2-New /> : <div onClick={() => this.onClick('child2')}><Child2 /></div>}
</div>
onClick(name) {
if (name === 'child1') {
this.setState({
showChild1: !this.state.showChild1,
});
} else if (name === 'child2') {
this.setState({
showChild2: !this.state.showChild2,
});
}
planning to achieve something like:
<div className="container">
<ToggleView />
{this.state.child2 ? <Child2-New /> : <div onClick={() => this.onClick('child2')}><Child2 /></div>}
</div>

If you're using Node.js it's quite simple to manage your components in separate JS files.
Create a new JS file - ToggleView.js - as an example.
var React = require('react');
module.exports = React.createClass({
render: function() {
return (
<div>
... Your markup etc here
</div>
);
});
And then you can require it from within the JS where you want to use it:
var ToggleView = require('ToggleView.js');
And then use it:
<div className="container">
<ToggleView />
</div>
Secondly, if your state is managed at the parent which you need your children to have access to, you can simply prop down to them.
function thisFunc(val) {
// do something
};
Prop the function to the child
<ToggleView handleFunc={this.thisFunc} />
And in ToggleView.js, if you needed your to trigger on click:
...
<a onClick={this.prop.handleFunc}>
<img ... />
</a>
...
In this scenario, we prop thisFunc down to the child which will allow you to set the logic at the parent, whether you need to set state or whatever.
Hopefully this helps!

Related

Apply the Array.map() method to the comment data stored in the parent's state and pass to child

I am just a beginner at learning React! (3 weeks). I cloned the Instagram main page for practicing and I tried to make a comment component and apply the Array.map() method to the comment data stored in the parent's state so that as many comment components as the number of comments appear. When I do this without comment component it works well
<ul className="feed-comments">
{/* <Comment commentAddList={this.states.commentList} /> */}
<li>hello</li>
{this.state.commentList.map((comm, idx) => {
return <li key={idx}>{comm}</li>;
})}
</ul>
However, when I create Comment Component and passing parent's state to child's component in Comment.js it doesn' work
and the error message : Cannot read properties of undefined (reading 'commentList')
<ul className="feed-comments">
<Comment commentAddList={this.states.commentList} />
</ul>
This is Comment.js in Component folder
import React, { Component } from 'react';
export class Comment extends Component {
render() {
return (
<>
{/* <li>hello</li> */}
{this.props.commentAddList.map((comm, idx) => {
return <li key={idx}>{comm}</li>;
})}
</>
);
}
}
export default Comment;
I will leave the whole code below just in case!
import React, { Component } from 'react';
// import "../../styles/common.scss";
import './Feed.scss';
import { FontAwesomeIcon } from '#fortawesome/react-fontawesome';
import {
faHeart,
faComment,
faPaperPlane,
faBookmark,
faEllipsisH,
} from '#fortawesome/free-solid-svg-icons';
import Comment from '../../../compoonents/Comment/Comment';
class Feed extends Component {
constructor() {
super();
this.state = {
value: '',
commentList: [],
};
}
getValue = event => {
this.setState({
value: event.target.value,
});
};
addComment = () => {
this.setState({
commentList: this.state.commentList.concat([this.state.value]),
value: '',
});
};
addCommEnter = e => {
if (e.key === 'Enter') {
this.addComment();
}
};
// enterClick = e => {
// if (e.key === 'Enter') {
// this.buttonClick;
// e.target.value = '';
// }
// };
render() {
return (
<div className="feeds">
<div className="article">
<div className="identi">
<img className="selfi-identi" alt="selfi-img" src="about.png" />
<span className="name"> Jiwan Jeon </span>
{/* <i id="test" class="fa fa-ellipsis-h" aria-hidden="true"></i> */}
<div className="faEllipsisH">
<FontAwesomeIcon icon={faEllipsisH} />
</div>
</div>
<div className="pic">
<img id="feed-pic" src="ucscPic.png" />
</div>
<div className="show-box">
<div className="reaction-icons">
<FontAwesomeIcon icon={faHeart} className="heart" />
<FontAwesomeIcon icon={faComment} className="comment" />
<FontAwesomeIcon icon={faPaperPlane} className="plane" />
<FontAwesomeIcon icon={faBookmark} className="bookMark" />
</div>
<div className="like-counts">
<span>like 4,000</span>
</div>
<div className="check-comments">
<span>
UC Santa Cruz will continue to offer most courses remotely or
online for spring and summer 2021, providing in-person
instruction for a small
</span>
<a id="space" href="">
expanding
</a>
<br />
Check the all comments
<ul className="feed-comments">
<Comment commentAddList={this.states.commentList} />
{/* <li>hello</li> */}
{/* {this.state.commentList.map((comm, idx) => {
return <li key={idx}>{comm}</li>;
})} */}
</ul>
</div>
</div>
<div className="comment">
<i className="fa fa-smile-o" />
<input
// onChange={this.textChange}
// onKeyPress={this.enterClick}
onKeyPress={this.addCommEnter}
onChange={this.getValue}
className="user-input"
type="text"
placeholder="Add Comment..."
/>
<button onClick={this.addComment} className="post">
Post
</button>
</div>
</div>
</div>
);
}
}
export default Feed;
It would really appreciate your comment!
I only glanced at this question so I don't know if this is the only problem, but:
<ul className="feed-comments">
<Comment commentAddList={this.states.commentList} />
</ul>
needs to be:
<ul className="feed-comments">
<Comment commentAddList={this.state.commentList} />
</ul>

How to make my functional Post component have certain linkable properties?

I'm new to React and haven't learned how to use databases and other functions as of yet and this is my first major learning React project. I'm trying to make my functional Post component link/route to a /profile/uniqueTweetId. Here is my Post component, to show you how I have set it up.
function Post({displayName,username,verified,text,image,avatar,comments,shares,likes,twitterId}) {
return (
<div className = "post">
<div className = "post__avatar">
<Avatar src={avatar} />
</div>
<div className = "post__body">
<div className = "post__header">
<div className = "post__headerText">
<h3>
{displayName} {""}
<span className = "post_headerSpecial">
{verified && <VerifiedUserIcon className="post__badge" />} #
{username}
</span>
</h3>
</div>
<div className = "post__headerDescription">
<p>{text}</p>
</div>
<img src= {image} alt= "" />
<div className = "post__footer">
<span className ="post__chatSpan"> <ChatBubbleOutlineIcon className = "post__chatStyling" fontSize="small" onClick={() => setCommentCount(commentCount + 1)} />
<span className = "post__chatFormating">{comments + commentCount} </span>
</span>
<span className ="post__repeatSpan"> <RepeatIcon className = "post__repeatStyling" fontSize="small" onClick={() => setRepeatCount(repeatCount + 1)} />
<span className = "post__repeatFormating">{shares + repeatCount}</span>
</span>
<span className ="post__favoriteSpan"> <FavoriteBorderIcon className = "post__favoriteStyling" fontSize="small" onClick={() => setLikeCount(likeCount + 1)} />
<span className = "post__favoriteFormating">{likes + likeCount}</span>
</span>
<PublishIcon fontSize="small" />
</div>
</div>
</div>
</div>
)
}
export default Post;
The problem arises when I render, the Post in my functional Feed component.
function Feed() {
return (
<Router>
<div className= "feed">
<Switch>
</Switch>
{/* Header */}
<div className= "feed__header">
<h2>Home</h2>
</div>
{/* TweetBox */}
<TweetBox />
{
listOfPosts.map(function (post) {
return (
< Post
displayName= {post.displayName}
username= {post.username}
verified= {post.verified}
text= {post.text}
avatar = "blah"
image = "blah"
comments = {post.comments}
shares = {post.shares}
likes = {post.likes}
twitterId ={post.twitterId}
/>
);
})
}
</div>
</Router>
)
}
export default Feed;
which listOfPosts is my array of hard coded "Post" prop variables that I'm currently looping through to render each post, so that in the future I could push the posts inside the array into a database when I'm ready. I'm struggling because I don't understand how to use React router in this context, because if I use Link inside the map function, All the props become a link, and I lose the functionality of my counters. I was hoping for ideas on how to attack this problem and to make my components work like an actual twitter post. Sorry for the long post it's my first StackOverflow question. Thank you again, any help is greatly appreciated!

React Hover to conditional render component

this is my code so far
class PortfolioList extends Component{
render(){
const {column , styevariation } = this.props;
const list = PortfolioListContent.slice(0 , this.props.item);
return(
<React.Fragment>
{list.map((value , index) => (
<div className={`${column}`} key={index}>
<div className={`portfolio ${styevariation}`}>
<div className="thumbnail-inner" >
<div className={`thumbnail ${value.image}`}></div>
<div className={`bg-blr-image ${value.image}`}></div>
</div>
<div className="content" >
<div className="inner">
<p>{value.category}</p>
<h4>{value.title}</h4>
<div className="btn-container">
<div className="portfolio-button">
<a className="rn-btn" href="/portfolio-details"><FaGithub /> Git </a>
</div>
<div className="portfolio-button">
<a className="rn-btn" href="/portfolio-details"><FaExternalLinkAlt /> Live </a>
</div>
</div>
</div>
</div>
</div>
</div>
))}
</React.Fragment>
)
}
}
I want to conditionally render the div "content" and the child elements of content div when mouse is hovering over "thumbnail-inner" div. But hide content when mouse is not hovering over thumbnail-inner div.
How can i achieve this?
I didn't test this, but the idea is to add a variable in the state of the component which holds the current hovered item.
When a mouseEnter event enters to your thumbnail-inner, you update that variable with the current component index. And you set it to -1 when a mouseLeave events happens in your thumbnail-inner.
Then you simply render the content conditionally by checking if the this.state.selectedIndex === index.
class PortfolioList extends Component {
state = {
selectedItem: -1,
}
render(){
const {column , styevariation } = this.props;
const list = PortfolioListContent.slice(0 , this.props.item);
return(
<React.Fragment>
{list.map((value , index) => (
<div className={`${column}`} key={index}>
<div className={`portfolio ${styevariation}`}>
<div
className="thumbnail-inner"
onMouseEnter={ () => { this.setState({selectedItem: index}) } }
onMouseLeave={ () => { this.setState({selectedItem: -1}) } }>
<div className={`thumbnail ${value.image}`}></div>
<div className={`bg-blr-image ${value.image}`}></div>
</div>
{
this.state.selectedItem === index &&
<div className="content" >
<div className="inner">
<p>{value.category}</p>
<h4>{value.title}</h4>
<div className="btn-container">
<div className="portfolio-button">
<a className="rn-btn" href="/portfolio-details"><FaGithub /> Git </a>
</div>
<div className="portfolio-button">
<a className="rn-btn" href="/portfolio-details"><FaExternalLinkAlt /> Live </a>
</div>
</div>
</div>
</div>
}
</div>
</div>
))}
</React.Fragment>
)
}
First, you need to add state for condition of hover (ex: "onHover"), the state is for conditional rendering the <div className="content">.
Second you need create function for hover and leaveHover(onMouseEnter & onMouseLeave) we call it handleMouseEnter for onMouseEnter, and we call it handleMouseLeave for onMouseLeave.
class PortfolioList extends Component {
state = {
onHover: false,
}
handleMouseEnter() {
this.setState({onHover: true})
}
handleMouseLeave() {
this.setState({onHover: false})
}
render(){
const {column , styevariation } = this.props;
const list = PortfolioListContent.slice(0 , this.props.item);
return(
<React.Fragment>
{list.map((value , index) => (
<div className={`${column}`} key={index}>
<div className={`portfolio ${styevariation}`}>
<div
className="thumbnail-inner"
onMouseEnter={this.handleMouseEnter}
onMouseLeave={this.handleMouseLeave}>
<div className={`thumbnail ${value.image}`}></div>
<div className={`bg-blr-image ${value.image}`}></div>
</div>
{
this.state.onHover &&
<div className="content" >
<div className="inner">
<p>{value.category}</p>
<h4>{value.title}</h4>
<div className="btn-container">
<div className="portfolio-button">
<a className="rn-btn" href="/portfolio-details"><FaGithub /> Git </a>
</div>
<div className="portfolio-button">
<a className="rn-btn" href="/portfolio-details"><FaExternalLinkAlt /> Live </a>
</div>
</div>
</div>
</div>
}
</div>
</div>
))}
</React.Fragment>
)
}

How to build Tabs component Reactjs

I'm trying to build a Tabs component with ReactJS and I'm following a CSS stylesheet.So, I would love to have this as render :
<div data-container="" class="tabs tabs-horizontal">
<div class="tabs-header">
<div class="tabs-header-tab ph active" data-tab="0" style="transform: translateX(0px) translateZ(0px);">Personal
</div>
<div class="tabs-header-tab ph undefined" data-tab="0" style="transform: translateX(0px) translateZ(0px);">Job
</div>
<div class="tabs-header-tab ph undefined" data-tab="0" style="transform: translateX(0px) translateZ(0px);">
Salary</div>
</div>
<div data-container="" class="tabs-content">
<div data-container="" class="tabs-content-tab open" data-tab="0">
<div>I am a HR Specialist.</div>
</div>
<div data-container="" class="tabs-content-tab undefined" data-tab="0">
<div>No records have been added yet</div>
</div>
<div data-container="" class="tabs-content-tab undefined" data-tab="0">
<div>This type of information needs to be added by your manager</div>
</div>
</div>
</div>
And this is what the components looks like now :
<Tabs>
<TabHeaders>
<TabHeadersItem text="Personal" state="active" />
<TabHeadersItem text="Job" />
<TabHeadersItem text="Salary" />
</TabHeaders>
<TabContents>
<TabContentsItem
content="I am a HR Specialist."
open="open"
/>
<TabContentsItem content="No records have been added yet" />
<TabContentsItem content="This type of information needs to be added by your manager" />
</TabContents>
</Tabs>
So, I'm trying to find a solution, when user clicks on a header it becomes "active" and its content "open" while the others should be closed and not active.
Ok so since you've edited your question, I'll do with mine. The idea is the same: To keep the state of which tab is open, and since you don't want to keep your tabs in a list, then you need to link a TabHeader to a TabContent:
const TabHeaderItem = props => {
return (
<div
onClick={() => props.changeTab(props.text.toLowerCase())}
className={props.state ? "active" : ""}
>
{props.text}
</div>
);
};
const TabContentsItem = props => {
return <div className={props.open ? "open" : "closed"}>{props.content}</div>;
};
const TabComponent = () {
const [active, setActive] = useState("personal");
const changeTab = tab => {
console.log("tab", tab);
setActive(tab);
};
return (
<div className="App">
<div className="tabs">
<TabHeaderItem
changeTab={changeTab}
text="Personal"
state={active === "personal"}
/>
<TabHeaderItem
changeTab={changeTab}
text="Job"
state={active === "job"}
/>
<TabHeaderItem
changeTab={changeTab}
text="Salary"
state={active === "salary"}
/>
</div>
<div className="tabs-content">
<TabContentsItem
content="I am a HR Specialist."
open={active === "personal"}
/>
<TabContentsItem
content="No records have been added yet"
open={active === "job"}
/>
<TabContentsItem
content="This type of information needs to be added by your manager"
open={active === "salary"}
/>
</div>
</div>
);
}
You can check out the working example here: https://codesandbox.io/s/exciting-gauss-lbghq

put elements into variable for naming (react)

I tried to put elements into CustomModal variable:
const CustomModal = (<div className="peoplelistpage-modal">
<div className="peoplelistpage-modal-content-empty" />
<div className="peoplelistpage-modal-content">
<CustomForm
krNameInput={this.state.krNameInput}
handleKrNameInput={this.handleKrNameInput}
enNameInput={this.state.enNameInput}
handleEnNameInput={this.handleEnNameInput}
positionInput={this.state.positionInput}
handlePositionInput={this.handlePositionInput}
departmentInput={this.state.departmentInput}
handleDepartmentInput={this.handleDepartmentInput}
doingInput={this.state.doingInput}
handleDoingInput={this.handleDoingInput}
btnValue="add"
onBtnClick={this.handlePersonAddBtn}
/>
</div>
<div className="peoplelistpage-modal-content-empty" />
</div>);
and used it in render() like this:
render() {
//...
{ CustomModal }
//...
but, got an error:
react-dom.development.js:57 Uncaught Invariant Violation: Objects are not valid as a React child (found: object with keys {CustomModal}). If you meant to render a collection of children, use an array instead.
Is there are any way to put elements into variable for naming?
Thanks.
----update-----
This is my full code of render :
render() {
const CustomModal = (<div className="peoplelistpage-modal">
<div className="peoplelistpage-modal-content-empty" />
<div className="peoplelistpage-modal-content">
<CustomForm
krNameInput={this.state.krNameInput}
handleKrNameInput={this.handleKrNameInput}
enNameInput={this.state.enNameInput}
handleEnNameInput={this.handleEnNameInput}
positionInput={this.state.positionInput}
handlePositionInput={this.handlePositionInput}
departmentInput={this.state.departmentInput}
handleDepartmentInput={this.handleDepartmentInput}
doingInput={this.state.doingInput}
handleDoingInput={this.handleDoingInput}
btnValue="add"
onBtnClick={this.handlePersonAddBtn}
/>
</div>
<div className="peoplelistpage-modal-content-empty" />
</div>);
const { people } = this.props.people.state;
return (
<React.Fragment>
{/* check login */}
{this.props.auth.state.isLoggedIn ? (
{ CustomModal }
) : (
<div />
)}
<div className="peoplelistpage-main">
<h1 className="peoplelistpage-title">people list</h1>
<div className="peoplelistpage-list-container">
{people.map((person, index) => (
<ul className="peoplelistpage-list-ul" key={index}>
<li className="peoplelistpage-list-li">
{`${index + 1}.`}{" "}
<Link to={`${this.props.location.pathname}/${person.id}`}>
{person.kr_name}
</Link>{" "}
<button onClick={this.handlePersonDeleteBtn(person.id)}>
<DeleteUserIcon />
</button>
</li>
</ul>
))}
</div>
<button onClick={this.openModal}>add</button>
</div>
</div>
) : (
<CustomNotPermittedForm />
)}
</React.Fragment>
);
}
Yes, you can use a div or a React.Fragment to group elements together. divs are added to the DOM while Fragments are not. But in order for this work with state, you will have to use a function, as a static variable does not get updated with state values.
const CustomModal = () => (
<React.Fragment> // <-- or div
<div className="peoplelistpage-modal">
<div className="peoplelistpage-modal-content-empty" />
<div className="peoplelistpage-modal-content">
<CustomForm
krNameInput={this.state.krNameInput}
handleKrNameInput={this.handleKrNameInput}
enNameInput={this.state.enNameInput}
handleEnNameInput={this.handleEnNameInput}
positionInput={this.state.positionInput}
handlePositionInput={this.handlePositionInput}
departmentInput={this.state.departmentInput}
handleDepartmentInput={this.handleDepartmentInput}
doingInput={this.state.doingInput}
handleDoingInput={this.handleDoingInput}
btnValue="add"
onBtnClick={this.handlePersonAddBtn}
/>
</div>
<div className="peoplelistpage-modal-content-empty" />
</div>
</React.Fragment>
);
Usage
render() {
// ...
<CustomModal />
// ...

Resources