Trying to get a simple fade in/out transition working.
I've tried moving the <CSSTransition> around into different areas to no avail. I'm using this successfully in another component that's mapping children but can't see why it wouldn't work in this case since I'm rendering it together with the child component, if the child gets returned at all.
Child component
const Error = (props) => {
return (
<CSSTransition timeout={400} classNames={errorTransition}>
<span> {props.errorString} </span>
</CSSTransition>
)
}
Parent component
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { CSSTransition } from 'react-transition-group';
import type { InfoState } from './state';
import { closeError } from './actions';
const mapStateToProps = (state: {info: InfoState}) => ({
info: state.info.data.info,
infoError: state.info.infoError,
});
const mapDispatchToProps = dispatch => ({
closeError: () => dispatch(closeError()),
});
class Parent extends Component<Props, State> {
state = { info: this.props.info };
handleChange = (e) => {
this.setState({ info: e.target.value });
this.props.closeError();
}
render() {
if (this.props.info === null) {
return (
<div className="info-wrapper">
<input
type="text"
value={this.state.info ? this.state.info : '' }
onChange={this.handleChange}
/>
</div>
<div className="info-error">
{ this.props.infoError !== ''
? <Error
key={this.state.info}
errorString={this.props.infoError}
/>
: null
}
</div>
)
}
return ( <div> things </div> )
}
}
CSS
.errorTransition-enter {
opacity: 0.01;
}
.errorTransition-enter-active {
opacity: 1;
transition: all 400ms ease-out;
}
.errorTransition-exit {
opacity: 1;
}
.errorTransition-exit-active {
opacity: 0.01;
transition: all 400ms ease-out;
}
I was having a similar issue with conditionally removing an element wrapped with <CSSTransition>. To solve the problem I wrapped the <CSSTransition> element with a <TransitionGroup> element and used its childFactory prop. The childFactory prop can be used like so:
<TransitionGroup
childFactory={child => React.cloneElement(child)}
>
<CSSTransition timeout={400} classNames={errorTransition}>
<span> {props.errorString} </span>
</CSSTransition>
</TransitionGroup>
Related
I received this error :
Line 21:28: React Hook "useSpring" cannot be called in a class component. React Hooks must be called in a React function component or a custom React Hook function react-hooks/rules-of-hooks.
I want to make a transition with the opacity and when I click the button appears the image or disappears.
import React, { Component } from 'react';
import { withTranslation } from 'react-i18next';
import { useSpring, config, animated } from "react-spring";
import './Experience.css';
class Experience extends Component {
constructor(props) {
super(props);
this.state = {
showA: false
};
}
render() {
// const [showA, setShowA] = useState(false);
const fadeStyles = useSpring({
config: { ...config.molasses },
from: { opacity: 0 },
to: {
opacity: this.state.showA ? 1 : 0
},
});
return (
<div style={{ padding: "15px" }} className="App">
<h2>Fade Demo</h2>
<div>
<animated.div style={fadeStyles}>
<img src={`https://a.wattpad.com/useravatar/valery2080.256.603024.jpg)`} alt="hola"/>
</animated.div>
<br />
<button onClick={() => this.setState(val => !val)}>Toggle</button>
</div>
</div>
);
}
}
export default withTranslation()(Experience);
You need to convert the class component to a functional component. Following is the implementation of Experience Component to a functional component.
Note: Make sure to add the CSS file in your implementation.
Following is the codesandbox link for your reference: https://codesandbox.io/s/jolly-wescoff-bnqm4
import React, { useState, Component } from "react";
import { withTranslation } from "react-i18next";
import { useSpring, config, animated } from "react-spring";
const Experience = () => {
const [showA, setShowA] = useState(false);
const fadeStyles = useSpring({
config: { ...config.molasses },
from: { opacity: 0 },
to: {
opacity: showA ? 1 : 0
}
});
return (
<div style={{ padding: "15px" }} className="App">
<h2>Fade Demo</h2>
<div>
<animated.div style={fadeStyles}>
<img
src={`https://a.wattpad.com/useravatar/valery2080.256.603024.jpg)`}
alt="hola"
/>
</animated.div>
<br />
<button onClick={() => setShowA(!showA)}>Toggle</button>
</div>
</div>
);
};
export default withTranslation()(Experience);
I'm also using semantic-ui-react. When I pass the child component down from the parent the css styling gets all messed up, I lose my images and the click doesn't work.
I can call the cardClickHandler method in the parent component and am console logging the correct child, i just can't get it to render (am not hitting the console.log in the child component).
I also tried to run the cardClickHandler method in the images container to pass it down but that didn't work.
please help and explain what i'm doing wrong. thanks!
images container:
import React from 'react';
import SearchBar from '../components/SearchBar';
import Images from '../components/Images';
import ImageCard from '../components/ImageCard';
class ImagesContainer extends React.Component {
state = {
images: [],
image: {},
sortValue: '',
inputValue: '',
};
componentDidMount() {
fetch('http://localhost:3000/images').then((resp) => resp.json()).then((resp) => {
this.setState({
images: resp
});
});
}
imageFilterOnChange = (event) => {
this.setState({
inputValue: event.target.value
});
};
sortImages = (images) => {
if (this.state.sortValue === 'location') {
return [ ...images ].sort((a, b) => {
if (a.location > b.location) {
return 1;
} else if (a.location < b.location) {
return -1;
} else {
return 0;
}
});
} else {
return images;
}
};
render() {
const filteredImages = this.state.images.filter((image) => {
return image.location.toLowerCase().includes(this.state.inputValue.toLowerCase());
});
return (
<div>
<Images
images={this.sortImages(filteredImages)}
onClick={this.cardClickHandler}
/>
<SearchBar
images={this.sortImages(filteredImages)}
imageFilterOnChange={this.imageFilterOnChange}
inputValue={this.state.inputValue}
onChange={this.handleSortImages}
/>
</div>
</div>
);
}
}
export default ImagesContainer;
parent component:
import React from 'react';
import ImageCard from './ImageCard';
import { Card, Image } from 'semantic-ui-react';
class Images extends React.Component {
state = {
image: []
};
cardClickHandler = (e) => {
let cardId = e.target.dataset.id;
this.props.images.find((image) => {
return image.id === cardId;
});
console.log('hi, cardId', cardId);
fetch(`http://localhost:3000/images/${cardId}`)
.then((resp) => resp.json())
.then((resp) => {
this.setState({
image: resp
})
console.log(this.state.image);
})
}
render() {
const allImages = this.props.images;
return allImages.map((image) => {
return (
<Card
key={image.id}
className="photo"
data-id={image.id}
data-name={image.name}
onClick={this.cardClickHandler}
>
<img
src={image.image}
alt=""
data-id={image.id}
data-name={image.name}
className="photo-image"
height={265}
/>
</Card>
);
});
}
}
export default Images;
child component:
i'm not hitting the console.log here, so no more code!
import React from 'react';
import { Card, Image } from 'semantic-ui-react';
class ImageCard extends React.Component {
render() {
console.log('image card');
return (
<Card>
</Card>
);
}
}
export default ImageCard;
I left a comment with a few improvements to the code you could make. Specifically:
You have an extra </div> in your ImagesContainer.
Also, you'll want to remove onClick={this.cardClickHandler} from ImagesContainer as cardClickHandler is defined not on ImagesContainer but instead on your Images component.
But the problem is that you are not rendering your ImageCard component at all. You are just rendering <Card> instead of <ImageCard>
Specifically, your parent component's render should change from this:
render() {
const allImages = this.props.images;
return allImages.map((image) => {
return (
<Card
key={image.id}
className="photo"
data-id={image.id}
data-name={image.name}
onClick={this.cardClickHandler}
>
<img
src={image.image}
alt=""
data-id={image.id}
data-name={image.name}
className="photo-image"
height={265}
/>
</Card>
);
});
}
to this:
render() {
const allImages = this.props.images;
return allImages.map((image) => {
return (
<ImageCard
key={image.id}
className="photo"
data-id={image.id}
data-name={image.name}
onClick={this.cardClickHandler}
>
<img
src={image.image}
alt=""
data-id={image.id}
data-name={image.name}
className="photo-image"
height={265}
/>
</ImageCard>
);
});
}
im trying to send a value from parent class to child but for some reason im getting props undefined any help?
this is parent class and sending the data to child.
I have added the full child code as requested. im not sure how to add props in as it is a function and when i tried adding props in im still getting props undefined error
{this.state.viewProfile ? (
<SideProfileDrawer
people={this.state.people}
viewprof={this.state.viewProfile}
/>
) : null}
here is me using the props in child
import { makeStyles } from "#material-ui/core/styles";
import InstructionsModal from "./instructionsmodal";
import List from "#material-ui/core/List";
import Divider from "#material-ui/core/Divider";
import React, { Component } from "react";
import Tooltip from "#material-ui/core/Tooltip";
import Drawer from "#material-ui/core/Drawer";
import Zoom from "#material-ui/core/Zoom";
import UserProfile from "../quiz/userProfile";
import { Button } from "react-bootstrap";
import { render } from "react-dom";
import Test from "../quiz/test";
export default function TemporaryDrawer(props) {
const useStyles = makeStyles({
list: {
width: 680
},
fullList: {
width: "auto"
}
});
const classes = useStyles();
const [state, setState] = React.useState({
top: false,
left: false,
bottom: false,
right: false
});
const toggleDrawer = (side, open) => event => {
if (
event.type === "keydown" &&
(event.key === "Tab" || event.key === "Shift")
) {
return;
}
setState({ ...state, [side]: open });
};
const sideList = side => (
<div
className={classes.list}
role="presentation"
onClick={toggleDrawer(side, false)}
onKeyDown={toggleDrawer(side, false)}
>
{this.props.people.map((person, index) => {
return (
<UserProfile
className="userProfile"
levelRook={person.levelRook}
levelStudent={person.levelStudent}
levelIntermediate={person.levelIntermediate}
levelExpert={person.levelExpert}
levelMaster={person.levelMaster}
score={person.Score}
question={person.Questions}
email={person.email}
time={person.lastLogin}
/>
);
})}
</div>
);
return (
<div>
{this.props.viewprof?sideList:null}
<Button onClick={toggleDrawer("right", true)}>Open Right</Button>
<Drawer
anchor="right"
open={state.right}
onClose={toggleDrawer("right", false)}
>
{sideList("right")}
</Drawer>
</div>
);
}
Any help in solving this i tried everything
don't use this.props just use props as you have stateless component not stateful read more
Hi I have the following React component that positions its children with styles.
const styles = () => ({
bathButt : {
top :278,
left : 336
},
})
class AudioZones extends Component {
render() {
const { classes } = this.props;
return (
<IconButton className={classes.bathButt} >
<Speaker/>
</IconButton>
);
}
}
export default withStyles(styles) (AudioZones);
I have created a child component "AudioZone"
render()
return (
);
}
which i substitute into the parent
render() {
const { classes } = this.props;
return (
<AudioZone/> );
}
However I have run into trouble on how I pass down the "bathButt" style so that the position of the button is set in the parent but read and rendered by the child.
Any help appreciated
For withStyles you can use Higher-Order Components (HOC) to pass styles from parent to child
const styles = () => ({
bathButt: {
top: 20,
left: 30,
backgroundColor: "blue"
}
});
const withMyStyles = WrappedComponent => {
const WithStyles = ({ classes }) => {
return (
<div>
<WrappedComponent classes={classes} />
</div>
);
};
return withStyles(styles)(WithStyles);
};
and use it in your child component
class AudioZones extends Component {
render() {
const { classes } = this.props;
return (
<IconButton className={classes.bathButt}>
<h1>Speaker Component</h1>
</IconButton>
);
}
}
export default withMyStyles(AudioZones);
but insted of withStyles you can use makeStyles,i think its easer
const useStyles = makeStyles({
bathButt: { top: 20, left: 50, color: "red" } // a style rule
});
function App(props) {
return <AudioZones useStyles={useStyles} />;
}
child component
function AudioZones(props) {
const classes = useStyles();
return (
<div>
<IconButton className={classes.bathButt}>
<h1>Speaker Component</h1>
</IconButton>
</div>
);
}
Working Codesandbox for withStyles and makeStyles
I'm using react-select along with material-ui to make a autocomplete component that looks and functions like the material ones.
I followed the basic setup here
https://material-ui.com/demos/autocomplete/
And then had to tweak to my setup with the data structure the way our API handles, this all works great but now I'm trying to allow the user to create a new option and I can't seem to get it to display the option back
Here is the component as is
import React, { Component } from 'react';
import { withStyles } from '#material-ui/core/styles';
import styles from "./styles";
import MenuItem from '#material-ui/core/MenuItem';
import Select from 'react-select';
import 'react-select/dist/react-select.css';
import Typography from '#material-ui/core/Typography';
import ArrowDropDownIcon from '#material-ui/icons/ArrowDropDown';
import ArrowDropUpIcon from '#material-ui/icons/ArrowDropUp';
import Input from '#material-ui/core/Input';
import LinearProgress from '#material-ui/core/LinearProgress';
import classNames from 'classnames';
class Option extends React.Component {
handleClick = event => {
this.props.onSelect(this.props.option, event);
};
render() {
const { children, isFocused, isSelected, onFocus } = this.props;
return (
<MenuItem
onFocus={onFocus}
selected={isFocused}
disabled={isSelected}
onClick={this.handleClick}
component="div"
style={{
fontWeight: isSelected ? 500 : 400,
}}
>
{children}
{children === 'LOADING...' &&
<LinearProgress style={{ position: 'absolute',width: '100%',bottom: '0',left: '0',height: '2px', }} />
}
</MenuItem>
);
}
}
class SelectWrapped extends Component {
render() {
const { classes, ...other } = this.props;
return (
<Select
optionComponent={Option}
noResultsText={<Typography>{'No results found'}</Typography>}
clearRenderer={() => {}}
arrowRenderer={arrowProps => {
return arrowProps.isOpen ? <ArrowDropUpIcon /> : <ArrowDropDownIcon />;
}}
valueComponent={valueProps => {
const { children } = valueProps;
console.log(children)
return <div className="Select-value">{children}</div>;
}}
{...other}
/>
);
}
}
class SelectCreatable extends Component {
render() {
const { classes, ...other } = this.props;
console.log(this.props)
return (
<Select.Creatable
optionComponent={Option}
noResultsText={<Typography>{'No results found'}</Typography>}
clearRenderer={() => {}}
arrowRenderer={arrowProps => {
return arrowProps.isOpen ? <ArrowDropUpIcon /> : <ArrowDropDownIcon />;
}}
valueComponent={valueProps => {
const { children } = valueProps;
return <div className="Select-value">{children}</div>;
}}
{...other}
/>
);
}
}
class AutoCompleteComponent extends Component {
state = {
value: null,
};
handleChange = value => {
this.setState({ value: value })
const foundSuggestion = this.props.suggestions.find((s) => s.id === value);
if (this.props.creatable) {
this.props.onChange(foundSuggestion || {
[this.props.labelPropName]: value
})
} else {
this.props.onChange(foundSuggestion)
}
}
onChange = value => {
this.props.onChange(this.props.suggestions.find((s) => s.id === value))
};
render() {
const { classes, labelPropName, creatable } = this.props;
const suggestions = this.props.suggestions.map(suggestion => ({
value: suggestion.id,
label: this.props.labelFunction(suggestion)
}))
return (
<div className={classNames(classes.root,this.props.className)}>
<Input
fullWidth
inputComponent={creatable ? SelectCreatable : SelectWrapped}
value={this.state.value}
onChange={(value) => this.props.showValue ? this.handleChange(value) : this.onChange(value)}
placeholder={this.props.placeholder}
classes={{
input: classes.input,
...this.props.InputClasses
}}
inputProps={{
classes,
simpleValue: true,
options: suggestions
}}
/>
</div>
);
}
}
export default withStyles(styles, { withTheme: true })(AutoCompleteComponent);
I setup a stackblitz with a running example and some options. If you type and select an option you'll see it display the selected option, but if you type a new one and hit enter it doesn't display the option and I'm trying to figure out why, some help on what I'm doing wrong here would be super helpful
https://wmazc4.stackblitz.io
I thinks the bug is with your data conversion id to value messes with your react-select component
I went through a demo from an exact copy of your code (since your example wasn't working)
here is my example: https://codesandbox.io/s/p9j3xz843m
here I used
inputProps={{
classes,
name: "react-select-single",
instanceId: "react-select-single",
simpleValue: true,
options: colourOptions,
valueKey: "id",
labelKey: "label"
}}
find that I used valueKey and labelKey props to convert data you can find more from the live example
hope this will help you. please let me know if you want more clarifications.