React is removing dom before ReactCSSTransitionGroup animation finishes - reactjs

I a component that is supposed to swap out a line of text with a list of icons. I am trying to animate the departure of the text and the entry of the icons using ReactCSSTransitionGroup. The entry of the icons works fine but react kills the dom of the text before the animation can run. here's the render state of the component:
render () {
return (
<section className="SocialBlock" onMouseOver={this.showIcons} onMouseLeave={this.hideIcons}>
{(() => {
if (this.state.iconsAreVisible) {
return (
<div className={`socialAccounts`}>
<ReactCSSTransitionGroup
transitionName="socialIcons"
transitionEnterTimeout={500}
transitionLeaveTimeout={300}
transitionAppear={true} >
{socials.map((icon, index) => {
return <div className={`icon icon-${index+1}`} key={index}><InlineSVG src={icon} /></div>
})}
</ReactCSSTransitionGroup>
</div>
)
} else {
return (
<ReactCSSTransitionGroup
transitionName="socialText"
transitionEnterTimeout={500}
transitionLeaveTimeout={500}
transitionAppear={true} >
<div key="12313"><h3>Check out the social stuff!</h3></div>
</ReactCSSTransitionGroup>)
}
})()}
</section>
);
}
I'm not sure why it's not working. I can switch my animation classes to appear instead of leave and it works for the entry - but the departure is still abrupt.

You are getting this behavior because of the structure of your component.
When (this.state.iconsvisible == false), then your entire second <ReactCSSTransitionGroup> will be unmounted, and will not be rendered.
And then it does not get the chance to do its leave transition.
Anything that needs to animate on leaving, should be inside the <ReactCSSTransitionGroup>.
To fix, you could do this:
<section>
{
<ReactCSSTransitionGroup>
{ if (this.state.iconsarevisible) {
socials.map(...)
}
}
</ReactCSSTransitionGroup>
<ReactCSSTransitionGroup>
{ if (!this.state.iconsarevisible) {
<div>Check out social stuff</div>
}
}
</ReactCSSTransitionGroup>
}
</section>

Related

React - onClick event not working correctly

I'm attempting to pass an onClick function as a prop to a child component in React. However, nothing is being logged to the console when the button is clicked. For now I'm just trying to console log to make sure the event is actually firing.
Any Ideas?
class App extends React.Component {
togglePallets = (pallet) => {
console.log('test');
}
render() {
return (
<div className="mainWrapper">
<div className="mainContainer">
<div>
<img src="images/picture-of-me.jpg" alt="Me"></img>
</div>
</div>
<SideBar toggle={this.togglePallets} showPallets={[this.state.showAboutPallet, this.state.showLanguagesPallet,
this.state.showProjectsPallet, this.state.showContactPallet]}/>
{this.state.showAboutPallet && <AboutPallet />}
{this.state.showAboutPallet && <LanguagesPallet />}
{this.state.showAboutPallet && <ProjectsPallet />}
{this.state.showAboutPallet && <ContactPallet />}
</div>
);
}
}
function SideBar(props) {
return (
<div className="sideBarContainer">
<Button icon={faUser} showAboutPallet={props.showPallets[0]} onClick={props.toggle}/>
</div>
);
}
What you have written is correct. But we can try it in another way using an arrow function.
onClick={(e) => props.toggle(e,data)}
And, make relevant changes in toggle function, so it may support multiple arguments.
Change your togglePallets to any of the below
togglePallets() {
console.log("test");
};
If you want to access event then
togglePallets(event) {
console.log("test");
};
Or
togglePallets=event =>{
console.log("teeventst");
};

How to render my Modal window and all the information contained inside ( in React)?

My application renders twelve random people fetched from a different website. Everything works fine apart from my modal component(it should render more information about the person you clicked). For some reason whenever I try to render it I get this error 'Modal.js:9 Uncaught TypeError: Cannot read property 'medium' of undefined' and more errors comes with it. I am printing props.modalInfo from the Modal component to the console and it does have all the information I need, but for some reasons it shows that props.modalInfo is undefined when I try to render it. I have never done modal box in React (I am a beginner). Could someone explain me how I can render my Modal and pass all the data successfully? Thank you in advance!
handleClick(id) {
this.setState((prevState) => {
const modalInfoToPass = prevState.employeeList.filter(employee =>
{
if(`${employee.name.first} ${employee.name.last}` === id){
// get only and only one object that fulfils the
// condition
return employee;
}
})
return {
displayModal: true,
// update the modalInfo state
modalInfo: modalInfoToPass
}
})
}
render(){
return (
<div className='container'>
<Header />
<main>
{
this.state.loading ? <h2 className='load-page'>Loading...</h2> :
this.state.employeeList.map(employee =>
<Employee key={`${employee.name.title}
${employee.name.last}`}
employeeInfo={employee}
**handleClick={this.handleClick}**
/>)
}
</main>
<Footer />
**{this.state.displayModal && <Modal modalInfo={this.state.modalInfo} />}**
</div>
);
}
function Modal(props) {
**console.log(props.modalInfo);**
return (
<div className='bg-modal'>
<div className='modal-content'>
<div className='modal-image'>
<img src={props.modalInfo.picture.medium} alt={`${props.modalInfo.name.title} ${props.modalInfo.name.first}`}/>
</div>
<div className='modal-info'>
<p className='name'>{props.modalInfo.name.first} {props.modalInfo.name.last}</p>
<p className='email'>{props.modalInfo.email}</p>
<p className='place'>{props.modalInfo.location.city}</p>
</div>
<hr />
<div className='modal-more-info'>
<p className='number'>{props.modalInfo.cell}</p>
<p className='address'>{`${props.modalInfo.location.street}, ${props.modalInfo.location.state}`}</p>
<p className='postcode'>{props.modalInfo.location.postcode}</p>
<p className='birthday'>{props.modalInfo.dob.date}</p>
</div>
</div>
</div>
);
}
What is id and is it on an employee? If it isn't available, you could just pass what you're filtering for in your handleClick:
handleClick={()=>this.handleClick(`${employee.name.first} ${employee.name.last}`)}
Or, you could just pass the employee:
handleClick={()=>this.handleClick(employee)}
and modify your handler:
handleClick(employee) {
this.setState({modalInfo: employee, displayModal: true})
}

Is there any obvious reason this won't render?

I'm pulling in an array of objects and mapping them to another component to be rendered.
renderRatings(){
if(this.props.ratings.length > 0){
return this.props.ratings.map(rating => {
<Rating
id={rating.id}
title={rating.title}
value={rating.value}
/>
});
}
}
This is where I render the rendering function.
render() {
return (
<div>
{this.renderRatings()}
</div>
);
}
}
This is the component I'm trying to populate and have rendered.
class Rating extends Component{
componentDidMount(){
console.log("props equal:", this.props)
}
render() {
return (
<div className="card darken-1" key={this.props._id}>
<div className="card-content">
<span className="card-title">{this.props.title}</span>
<p>{this.props.value}</p>
<button>Edit</button>
<button onClick={() => this.deleteRating(this.props._id)}>Delete</button>
</div>
</div>
);
}
}
export default connect({ deleteRating })(Rating);
No errors are being thrown, but when the page loads, the surrounding menu comes up, and the fetch request returns an array and supposedly maps it to the 'Rating' component, but no mapped Rating cards appear.
in your map, you're not returning the Rating etc... because you used { to define a code block, you have to type return. And since it's multi-line, use parens to mark the start and end of the Rating component.
return this.props.ratings.map(rating => {
<Rating
id={rating.id}
title={rating.title}
value={rating.value}
/>
needs to be
return this.props.ratings.map(rating => {
return (<Rating
id={rating.id}
title={rating.title}
value={rating.value}
/>)

My Toaster component is not creating multiple toasters on multiple clicks. Reactjs

I have made a toaster component which is only rendering 1 toaster on 1 or multiple clicks, but I need a component the renders multiple toasters on multiple clicks.
This is my Toaster Component.
import React, {Component} from 'react'
import '../stylesheets/adminlte.css'
ToastMsg = (props) => (
<div className=" snackbar" key={props.idx}>
<div className="card-header">
<h3 className="card-title">Toast</h3>
</div>
<div className="card-body">{props.message}</div>
<div className="card-footer"/>
</div>
)
createtoaster = () => {
if (this.state.show) {
return this
.state
.message
.map((msg, idx) => <ToastMsg idx={idx} message={msg}/>)
} else {
return null;
}
}
render() {
return (
<div className="col-md-2 offset-md-9">
<button className="btn btn-primary" onClick={this.handleOpen}></button>
{this.createtoaster()}
</div>
)
}
I am providing this.state.message from another component and passsing it via props. I cannot use any Library as per the requirement so if anyone can help me with this, It is appreciated. Also feel free to point out any mistakes in my code.
missing array element 'picker': < div className="card-body">{this.state.message [i] }
I would use map, too ... with key property for each item.
Are you sure you're receiving array with more elements ?

react: fade-in/slide-in animation when render component

I'm new in React. I have made a small app with a button and a list of image urls. When button is clicked, an image url is added to the list. I render the list of image urls with standard .map function.
I would like to make a fast ui animation effect when the image is displayed: a combination of fade-in and slide-in from left. I tried Velocity.js and found the velocity-react wrapper. But I can not understand how to use it. The same goes for the 'standard' velocity-animate library.
What is best? velocity-react, velocity-animate or something else?
And how do I do it?
JSX
<div className="row">
{
this.state.images.map( (image, index) => { return this.renderThumb(image, index); } )
}
</div>
renderThumb function
renderThumb(image, index) {
return (
<div ref="tweetImage" key={`image-${index}`} className="col-xs-3 tweetImage">
<img className="img-thumbnail" src={image} alt="my pic"/>
</div>
);
}
velocity-react
I tried to wrap <img> animation opacity from 0 to 1 like this (copied from docs):
<VelocityComponent animation={{ opacity: 1 }} duration={ 500 }>
<img className="img-thumbnail" src={image} alt="my pic"/>
</VelocityComponent
I keep getting this error:
Warning: React.createElement: type is invalid -- expected a string (for built-in components) or a class/function (for composite components) but got: object
No luck with ReactCSSTransitionGroup either (like suggestions below). Images are shown but without animation:
renderThumb(image, index) {
return (
<div ref="tweetImage" key={`image-${index}`} className="col-xs-3">
<ReactCSSTransitionGroup
transitionName="example">
<img className="img-thumbnail" src={image} alt="Ole Frank Jensen"/>
</ReactCSSTransitionGroup>
</div>
);
}
SOLVED:
I moved <ReactCSSTransitionGroup transitionName="example"> outside of the fading component and voilá :-)
render()
<div className="row">
<ReactCSSTransitionGroup transitionName="example">
{
this.state.images.map( (image, index) => { return this.renderThumb(image, index); } )
}
</ReactCSSTransitionGroup>
</div>
renderThumb()
renderThumb(image, index) {
return (
<div key={`image-${index}`} className="col-xs-3">
<img className="img-thumbnail" src={image} alt="Ole Frank Jensen"/>
</div>
);
}
You can use the CSSTransitionGroup provided by react.
https://facebook.github.io/react/docs/animation.html
a simple todo exammple from the docs
class TodoList extends React.Component {
constructor(props) {
super(props);
this.state = {items: ['hello', 'world', 'click', 'me']};
this.handleAdd = this.handleAdd.bind(this);
}
handleAdd() {
const newItems = this.state.items.concat([
prompt('Enter some text')
]);
this.setState({items: newItems});
}
handleRemove(i) {
let newItems = this.state.items.slice();
newItems.splice(i, 1);
this.setState({items: newItems});
}
render() {
const items = this.state.items.map((item, i) => (
<div key={item} onClick={() => this.handleRemove(i)}>
{item}
</div>
));
return (
<div>
<button onClick={this.handleAdd}>Add Item</button>
<ReactCSSTransitionGroup
transitionName="example"
transitionEnterTimeout={500}
transitionLeaveTimeout={300}>
{items}
</ReactCSSTransitionGroup>
</div>
);
}
}
i'd recommend going with React CSS Transistion Group module. It provides an high level animation wrapper for simple animations.
EDIT:
The link will permanently redirect to Animation Add-Ons
ReactTransitionGroup and ReactCSSTransitionGroup have been moved to the react-transition-group package that is maintained by the community.
From the docs
.example-enter {
opacity: 0.01;
}
.example-enter.example-enter-active {
opacity: 1;
transition: opacity 500ms ease-in;
}
.example-leave {
opacity: 1;
}
.example-leave.example-leave-active {
opacity: 0.01;
transition: opacity 300ms ease-in;
}
Where example will be the transistionName for the component that you wish to paint. and -enter,enter-active,-leave,-leave-active stand for the corresponding ticks of the animation cycle. These will be added by React internally as class names to the items.
You can use them to achieve the desired effect in question. A small demo here.
P.S: not sure if this outperforms Velocity.js, havent used that.

Resources