I have a js file handling my css where I am trying to change the value of an object, but the value stays the same.
let inputBoxInner = {
width: "80%",
marginTop: 5,
alignItems: "center",
color: "#397185",
cursor: "text",
height: 36,
border: "1px solid #80cfc6",
visibility: "visible",
opacity: 0.2,
setOpacity: function (e) {
this.opacity = e
};
};
module.exports = {
inputBoxInner
};
import React, {Component} from "react";
import {inputBoxInner} from "../css/style.js";
export default class Input extends Component {
state = {
borderOpacity: 1,
id: ""
};
return(
<div
className="input"
onClick={(e) => {
inputBoxInner.setOpacity(this.state.borderOpacity);
this.setState({id: e.target.className});
}}
style={inputBoxInner}
/>
);
};
I assume the "this.opacity" is only returning a reference and not modifying the actual object and I am unsure of how to make this object mutable.
How would I go about changing this value?
You should save a clicked state in the state and set opacity depending on it.
state = {
borderOpacity: 1,
id: "",
isClicked: false
};
return(
<div
className="input"
onClick={(e) => { this.setState({id: e.target.className, isClicked: true }); }}
style={{...inputBoxInner, opacity: this.state.isClicked ?
this.state.borderOpacity : inputBoxInner.opacity}}
/>
);
Related
I am trying to animate the transition of a list when filtered using the new useTransition hook changes in react-spring v9.x so that as list items are filtered the remaining items move to their new positions.
So far I have managed to get components in the list to fade in and out but the remaining components just jump to their new positions instantly once the fade out animation has completed. I have not been able to change this.
How do I animate the remaining components to smoothly move to their new locations?
Here is a code sandbox link to the current code.
You can see the jumping effect clearest if you type 'p' into search bar and watch the component with the name Plum jump up after a short delay.
App.js
import { useState } from "react";
import { useSpring, useTransition, animated } from "react-spring";
export default function App() {
const [items, setItems] = useState([
{ name: "Apple", key: 1 },
{ name: "Banana", key: 2 },
{ name: "Orange", key: 3 },
{ name: "Kiwifruit", key: 4 },
{ name: "Plum", key: 5 }
]);
const [searchText, setSearchText] = useState("");
const filteredItems = items.filter((item) =>
item.name.toLowerCase().includes(searchText.toLowerCase())
);
const transition = useTransition(filteredItems, {
from: { opacity: 0 },
enter: { opacity: 1 },
leave: { opacity: 0 }
});
const fadeInListItems = transition((style, item) => {
return (
<animated.div style={style}>
<Item data={item} />
</animated.div>
);
});
const handleSearchBarChange = ({ target }) => setSearchText(target.value);
return (
<div className="App">
<h2>Click on an item to toggle the border colour.</h2>
<SearchBar onChange={handleSearchBarChange} value={searchText} />
{fadeInListItems}
</div>
);
}
const SearchBar = (props) => {
return (
<>
<label>Search Bar: </label>
<input onChange={props.onChange} value={props.searchText} type="text" />
</>
);
};
const Item = (props) => {
const [isClicked, setIsClicked] = useState(false);
const [styles, api] = useSpring(() => ({
border: "2px solid black",
margin: "5px",
borderRadius: "25px",
boxShadow: "2px 2px black",
backgroundColor: "white",
color: "black"
}));
const handleClick = (e) => {
api.start({
backgroundColor: isClicked ? "white" : "red",
color: isClicked ? "black" : "white"
});
setIsClicked((prev) => !prev);
};
return (
<animated.div style={styles} onClick={handleClick} key={props.data.key}>
{props.data.name}
</animated.div>
);
};
You can achieve that effect by hiding the filtered elements with max-height (along with fade). This way the items will "collapse" rather than just fade so remained elements will "slide" up.
The transision
const transition = useTransition(filteredItems, {
from: { opacity: 0, marginTop: 5 },
enter: { opacity: 1, maxHeight: 50, marginTop: 5 },
leave: { opacity: 0, maxHeight: 0, marginTop: 0 }
});
I also added overflow: hidden to complete the effect of maxHeight and removed the margin: 5px of the Item because I added margin in the transition --definition.
const [styles, api] = useSpring(() => ({
border: "2px solid black",
-- margin: "5px",
borderRadius: "25px",
boxShadow: "2px 2px black",
backgroundColor: "white",
color: "black",
++ overflow: "hidden",
}));
https://codesandbox.io/s/react-spring-demo-change-border-colour-on-click-forked-7fdkl
I am trying to attach a custom slider component in an MUI Modal component.
My slider is working pretty good on a storybook, this is the behavior as expected:
But when I add it into the Material UI modal it this is the behavior:
I really don't know what could be happening... I've tried making my custom modal (without MUI), using another slider library and they all behave the same.
I am getting this warning when I try to move my slider on the modal:
Slider.js:770 [Violation] Added non-passive event listener to a scroll-blocking 'touchstart' event.
Consider marking the event handler as 'passive' to make the page more responsive.
See https://www.chromestatus.com/feature/5745543795965952
This is my slider code (which, to make emphasis, is working perfectly outside of the modal:
import React from "react";
import {
styled,
Grid,
Slider as MUISlider,
InputBase,
Tooltip,
} from "#material-ui/core";
const CustomSlider = styled(MUISlider)(({ theme }) => ({
color: theme.palette.secondary.light,
width: 86,
}));
const GasInput = styled(InputBase)(({ theme }) => ({
color: theme.palette.secondary.light,
width: 48,
height: 32,
border: "1px solid #ECEFF3",
borderRadius: 4,
background: "#FAFCFF",
fontSize: 12,
boxSizing: "border-box",
padding: 12,
}));
const SliderContainer = styled(Grid)({
width: 200,
height: 20,
marginTop: -10,
});
const Input = styled(Grid)({
paddingLeft: 8,
});
export interface SliderProps {
value: number;
min: number;
max: number;
onChangeValue: (value: number) => void;
}
interface Props {
children: React.ReactElement;
open: boolean;
value: number;
}
function ValueLabelComponent(props: Props) {
const { children, open, value } = props;
return (
<Tooltip open={open} enterTouchDelay={0} placement="top" title={value}>
{children}
</Tooltip>
);
}
export function Slider({ min, max, value, onChangeValue }: SliderProps) {
const handleSliderChange = (
_: React.ChangeEvent<unknown>,
value: number | number[]
) => {
onChangeValue(Number(value));
};
const handleInputChange = (event: React.ChangeEvent<HTMLInputElement>) => {
onChangeValue(parseInt(event.target.value, 10));
};
return (
<SliderContainer
container
direction="row"
alignItems="center"
justify="flex-end"
>
<Grid item>
<CustomSlider
ValueLabelComponent={ValueLabelComponent}
min={min}
max={max}
value={value}
onChange={handleSliderChange}
/>
</Grid>
<Input item>
<GasInput type="number" value={value} onChange={handleInputChange} />
</Input>
</SliderContainer>
);
}
I created an example using your code. Everything appears to work as expected. Compare your local code to that.
Thanks to #jack.benson answer, I was able to find out what was really going on (Really appreciated sir).
I created a modal component which abstracted the main things of the modal I will use through the entire app:
import React from "react";
import { Modal as MUIModal, Box, styled } from "#material-ui/core";
interface ModalProps {
width: number;
height: number;
children: React.ReactNode;
open: boolean;
}
export function Modal({ width, height, children, open }: ModalProps) {
const ModalContainer = styled(MUIModal)({
height,
width,
margin: "auto",
borderRadius: 12,
});
const ModalBox = styled(Box)({
height,
width,
background: "#FFFFFF",
borderRadius: 12,
outline: "none",
});
return (
<ModalContainer open={open}>
<ModalBox>{children}</ModalBox>
</ModalContainer>
);
}
As you can see, I am using the styled function in order to style my components. And that's what was giving me the problem. I don't know why is the reason, but if I move from styled to makeStyles it will work perfectly, this is the new code of my modal component:
import React from "react";
import { Modal as MUIModal, Box, makeStyles } from "#material-ui/core";
interface ModalProps {
width: number;
height: number;
children: React.ReactNode;
open: boolean;
}
const useStyles = ({ height, width }: Partial<ModalProps>) => makeStyles({
root: {
height: `${height}px`,
width: `${width}px`,
margin: "auto",
borderRadius: 12,
},
box: {
height: `${height}px`,
width: `${width}px`,
background: "#FFFFFF",
borderRadius: 12,
outline: 0,
}
});
export function Modal({ width, height, children, open }: ModalProps) {
const classes = useStyles({ width, height })()
return (
<MUIModal className={classes.root} open={open}>
<Box className={classes.box}>{children}</Box>
</MUIModal>
);
}
I am creating a component that animates a group of buttons in an elastic staggered way using react-native-pose. The buttons them selves use pose to animate the pressed state. I have almost got it looking how I want it although I'm not sure I'm doing things correctly.
This is what I want to achhieve...
... However the text looks awful like its got jpg artefacts on it :
App.js
import React, { Component } from 'react';
import styled from 'styled-components';
import posed from 'react-native-pose';
import Button from './src/components/Button';
const ScreenContainer = styled.View({
flex: 1,
padding: 20,
marginTop: 100
});
const Buttons = posed.View({
visible: {
staggerChildren: 100
},
hidden: {
staggerChildren: 100
}
});
export default class App extends Component {
state = {
buttonPose: 'hidden'
};
items = [
{ id: 0, label: 'One' },
{ id: 1, label: 'Two' },
{ id: 2, label: 'Three' }
];
componentDidMount = () => {
this.setState({
buttonPose: 'visible'
});
};
render() {
return (
<ScreenContainer>
<Buttons pose={this.state.buttonPose}>
{this.items.map(item => (
<Button label={item.label} key={item.id} />
))}
</Buttons>
</ScreenContainer>
);
}
}
Button.js
import React, { PureComponent } from 'react';
import { TouchableWithoutFeedback } from 'react-native';
import styled from 'styled-components';
import posed from 'react-native-pose';
const Container = styled(
posed.View({
visible: {
opacity: 1,
x: 0
},
hidden: {
opacity: 0,
x: -100
}
})
)({
marginBottom: 20
});
const Background = styled(
posed.View({
// If I comment out these poses the problem goes away
pressIn: {
scale: 1.1
},
pressOut: {
scale: 1
}
})
)({
padding: 20,
backgroundColor: '#f9415d',
borderRadius: 10
});
const Label = styled.Text({
fontSize: 18,
color: 'white',
textAlign: 'center'
});
export default class Button extends PureComponent {
state = {
buttonPose: 'pressOut'
};
onPressIn = () => {
this.setState({
buttonPose: 'pressIn'
});
};
onPressOut = () => {
this.setState({
buttonPose: 'pressOut'
});
};
componentDidMount = () => {};
render() {
const { onPressIn, onPressOut } = this;
const { buttonPose } = this.state;
const { label } = this.props;
return (
<Container>
<TouchableWithoutFeedback onPressIn={onPressIn} onPressOut={onPressOut}>
<Background pose={buttonPose} withParent={false}>
<Label>{label}</Label>
</Background>
</TouchableWithoutFeedback>
</Container>
);
}
}
Can anyone offer any insight into why the text and also the rounded corners look so artifacted and low res?
I have Tab navigator that handles data changing of itself and other two sibling component.
Main parent Component that does data fetching and manipulation based on three sentiments: positive, negative and neutral as request body parameter in http post request.
Second parent component that stores all positive data, negative data and neutral data from main parent component.
Then three Child Components: Table one and Tab Navigation.
The Tab navigation has three three tabs namely: Positive, Negative and Neutral.
As soon as the page renders on first load, by default (without clicking positive tab button), it fetches positive data and displays it in all three child components. Then on clicking on Negative tab, it should display negative data in all three child components i.e. Table one and under negative tab of tab navigation. Same thing follows for Neutral Tab.
In short, Tab navigation handles data rendering of it's self and sibling components based on its active state and getting that data from parent component.
I tried passing the active event from tab navigation to its upper container but it doesn't seem to work fine.
Tab.js
import React, { Component } from 'react';
export default class Tab extends Component
{
constructor(props)
{
super(props);
this.state =
{
active: 'positive',
}
}
toggle = (event) =>
{
this.setState({
active: event
})
this.props.sendEvent(this.state.active);
}
get_tab_content =()=>
{
switch(this.state.active)
{
case 'positive':
return <div><SomeDataComponent1 positiveprops={} /></div>;
case 'negative':
return <div><SomeDataComponent2 negativeprops={}/></div>;
case 'neutral':
return <div><SomeDataComponent3 neutralprops={} /></div>;
default :
}
}
render() {
const tabStyles = {
display: 'flex',
justifyContent: 'center',
listStyleType: 'none',
cursor: 'pointer',
width: '100px',
padding: 5,
margin: 4,
fontSize: 20,
color: 'green'
}
const tabStyles2 = {
display: 'flex',
justifyContent: 'center',
listStyleType: 'none',
cursor: 'pointer',
width: '100px',
padding: 5,
margin: 4,
fontSize: 20,
color: 'red'
}
const tabStyles3 = {
display: 'flex',
justifyContent: 'center',
listStyleType: 'none',
cursor: 'pointer',
width: '100px',
padding: 5,
margin: 4,
fontSize: 20,
color: 'yellow'
}
const linkStyles = {
display: 'flex',
justifyContent: 'center',
color: '#000',
listStyleType: 'none'
}
const divStyle = {
border: '1px solid #34baa2',
width: '450px'
}
const box = this.get_tab_content()
return (
<div style={divStyle} >
<ul style={linkStyles}>
<li style={tabStyles} onClick={function(){this.toggle('positive')}.bind(this)}>Positive</li>
<li style={tabStyles2} onClick={function(){this.toggle('negative')}.bind(this)}>Negative</li>
<li style={tabStyles3} onClick={function(){this.toggle('neutral')}.bind(this)}>Neutral</li>
</ul>
<div>
{box}
</div>
</div>
);
}
}
Second Parent Component.js
import React,{Component} from 'react';
import Tab from '../tab/tab';
import MentionTable from '../table/table';
class DataCharts extends Component{
constructor(props){
super(props);
this.state = {
childEvent: ''
}
}
getEvent = (childevent) => {
this.setState({
childEvent: childevent
});
console.log(this.state.childEvent)
}
render(){
const {positivetable,positivewords, negativetable, negativewords, neutraltable, neutralwords } = this.props;
return(
<div style={{display:'flex', flexDirection: 'row'}}>
<Table />
<Tab sendEvent={this.getEvent}/>
</div>
)
}
}
export default DataCharts;
The problem with your code is the next lines:
toggle = event => {
this.setState({
active: event
});
this.props.sendEvent(this.state.active);
};
setState is asynchronous, so you sending to sendEvent the not intended state.
toggle = event => {
this.setState(prevState => {
console.log('prevState', prevState);
console.log(event);
this.props.sendEvent(event);
return { active: event };
});
};
I think calling the parent function in setState callback would work, for thet we need to do it like this in Tab.js
this.setState({
active: event
}, () => { this.props.sendEvent(this.state.active)})
also console.log(this.state.childEvent) should be also in callback too so that you get the state after it has been updated, we need to change DataCharts.js too
this.setState({
childEvent: childevent
}, () => { console.log(this.state.childEvent)})
Working demo -: https://stackblitz.com/edit/react-zhbmad
so basically what I want to reach is to get dimensions of the div element inside return method of component. I get reference to this by ref and I want to get its width and height with getBoundingClientRect() but there is error: Uncaught TypeError: Cannot read property 'getBoundingClientRect' of undefined. I also tried offsetWidth and offsetHeight.
Here is my code:
import React from 'react';
import ReactDOM from 'react-dom';
import Style from 'style-it';
var Ink = require('react-ink');
import FontIcon from '../FontIcon/FontIcon';
var IconButton = React.createClass({
getInitialState() {
return {
iconStyle: this.props.iconStyle,
style: this.props.style,
cursorPos: {},
};
},
extend(obj, src) {
Object.keys(src).forEach(function(key) { obj[key] = src[key]; });
return obj;
},
Tooltip() {
var box = this.refs.button.getBoundingClientRect(),
Height = box.clientHeight,
tooltipStyle = {
};
return <div className="tooltip" style={tooltipStyle}>{this.props.tooltip}</div>;
},
showTooltip(){
},
removeTooltip(){
},
render() {
var _props = this.props,
Tooltip = this.Tooltip,
opts,
disabled = false,
rippleOpacity,
outterStyleMy = {
border: "none",
outline: "none",
padding: "8px 10px",
backgroundColor: "red",
borderRadius: 100 + "%",
cursor: "pointer",
},
iconStyleMy = {
fontSize: 12 + "px",
textDecoration: "none",
textAlign: "center",
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
},
rippleStyle = {
color: "rgba(0,0,0,0.5)",
};
if (_props.disabled || _props.disableTouchRipple) {
rippleStyle.opacity = 0;
};
if (_props.disabled) {
disabled = true;
};
if (this.state.labelStyle) {
iconStyleMy = this.state.iconStyle;
};
if (this.state.style) {
outterStyleMy = this.state.style;
};
if (_props.href) {
opts.href = _props.href;
};
var buttonStyle = this.extend(outterStyleMy, iconStyleMy);
return(
<Style>
{`
.IconButton{
position: relative;
}
.IconButton:disabled{
color: ${_props.disabledColor};
}
.btnhref{
text-decoration: none;
}
`}
<a {...opts} className="btnhref" >
<Tooltip />
<button ref="button" className={"IconButton" + _props.className} disabled={disabled} style={buttonStyle}
onMouseEnter={this.showTooltip} onMouseLeave={this.removeTooltip} >
<Ink background={true} style={rippleStyle} opacity={rippleOpacity} />
<FontIcon className={_props.iconClassName}/>
</button>
</a>
</Style>
);
}
});
ReactDOM.render(
<IconButton href="" className="" iconStyle="" style="" iconClassName="face" disabled="" disableTouchRipple="" tooltip="aaaaa" />,
document.getElementById('app')
);
So... I don't know how to accomplish this.
You can't get a reference to a DOM node before it was rendered.
Do your this.refs.button.getBoundingClientRect() in the componentDidMount lifecycle method to be sure it was rendered and you can get a reference to it.