How to fix translate which contains state, which changed by 'interval' (React) - javascript

I have a procedure for a timer for animation. I want to make an animation of logos like https://stripe.com/us/customers. But I have an endless loading of the page, so it doesn't work.
I tried to use a procedure in different parts of the code and tried to change interval for better optimization (I think my PC can't work with 1 ms interval), but it didn't help me.
It all from one file.
State:
class Home extends React.Component {
constructor(props) {
super(props);
this.state = {
submitError: false,
width: 0,
height: 0,
timer: 0
};
Procedure:
TimeForLogos() {
const time = setInterval(() => {
const passedTime = this.state.timer + 0.1;
if (passedTime === 20) {
clearInterval(time);
}
this.setState({
timer: passedTime,
});
}, 100);
}
I try to use it in render (I need that procedure begins when the site is opened) and try to make a button (I thought it help me to solve the problem of endless loading). So part of code from render for now:
<div className={s.logos}>
<span onClick={this.TimeForLogos()}>go</span>
{LogoData.map(logo => (
<div
className={s.logo}
style={{
right: `${logo.positionX}px`,
top: `${logo.positionY}px`,
width: logo.width * 1.1,
padding: `${(logo.width - logo.height) / 2} 0`,
transform: `translate(${this.state.timer * 10}px,0) scale(1)`,
}}
>
<img
src={logo.img}
alt=""
style={{
width: logo.width,
height: logo.height,
}}
/>
</div>
))}
</div>
So, a question. How can I update my code that it works? And I need to make so that procedure works when the site is opening (animation must play when the site is opened). How I can do it?

You can create a separate component and handle the transition of each component in the timeout function.
class Home extends Component {
constructor(props) {
super(props);
this.logoData = [{
width: 100,
height: 100,
text: "text1"
},
{
width: 100,
height: 100,
text: "text2"
},
{ width: 100,
height: 100,
text: "text3"
}];
}
render() {
return (
<div className="mainContainer">
{this.logoData.map(item => <MovingDiv {...item}/>)}
</div>
);
}
}
Creating one more react-component say MovingDiv.
class MovingDiv extends Component {
constructor(props) {
super(props);
this.state = {
translateX: 0,
translateY: 0,
scale: 0
}
}
componentDidMount() {
const intervalLimit = setInterval(() => {
let { translateX, translateY} = this.state;
// logic of setting translateX goes here
if(--translateX < -300) { // -300 is just for example
translateX = 0;
}
this.setState({
translateX
})
}, 200)
}
/* will move the divs towards right every 200ms*/
render() {
return(<div style={{ width: this.props.width, height: this.props.height, transform: `translate(${this.state.translateX}px, 0px)`}}>{this.props.text}</div>);
}
}
Hope this helps!

I updated something in code of previous commentator. I make everything in one class (Home). I make json file for logos and info contains in this file. So it's my code.
class Home extends React.Component {
constructor(props) {
super(props);
this.state = {
translateX: 0,
};}
render() {
setInterval(() => {
let { translateX } = this.state;
translateX -= 2;
if (translateX < -1800) {
translateX = 0;
}
this.setState({
translateX,
});
}, 1000);
<div className={s.logos}>
{LogoData.map(logo => (
<div
className={s.logo}
style={{
left: `${logo.positionX}px`,
top: `${logo.positionY}px`,
width: logo.width * 1.1,
padding: `${(logo.width - logo.height) / 2} 0`,
transform: `translate(${this.state.translateX}px,0) scale(1)`,
}}
>
<img
src={logo.img}
alt=""
style={{
width: logo.width,
height: logo.height,
}}
/>
</div>
))}
</div>

Related

Show/Hide React Component based on State

I am very new to React and am trying to create a page where clicking on the color square will show the hex code for that color. I've tried a bunch of different things and I can't figure out if my problem is in the event handling, in the state handling, both, or in something else altogether. I can get the hex code to either be there or not, but not have it change when I click.
Here is my main:
<main>
<h1>Dynamic Hex Code Display</h1>
<div id="container"></div>
<script type="text/babel">
class ColorSquare extends React.Component {
render() {
var blockStyle = {
height: 150,
backgroundColor: this.props.color,
};
return <div style={blockStyle} onClick = {this.props.onClick}></div>;
}
}
class HexDisplay extends React.Component {
render() {
var hexText = {
fontFamily: "arial",
fontWeight: "bold",
padding: 15,
margin: 0,
textAlign: "center",
};
var hexTextVis = {
...hexText,
visibility: "visible"
}
var hexTextInvis = {
...hexText,
visibility: "hidden"
}
var isVisible = this.props.isVisible;
if (isVisible) {
return <p style={hexTextVis}>{this.props.color}</p>;
} else {
return <p style={hexTextInvis}>{this.props.color}</p>;
}
}
}
class HexParent extends React.Component {
constructor(props) {
super(props);
this.state = {
isVisible: false
};
this.handleClick = this.handleClick.bind(this);
}
handleClick(e) {
this.setState(currentVis => ({isVisible: !currentVis.isVisible}));
console.log(this.state);
console.log('clicking');
}
render() {
var fullBoxStyle = {
padding: 0,
margin: 10,
backgroundColor: "#fff",
boxShadow: "3px 3px 5px #808080",
boxRadius: "5px 5px",
height: 200,
width: 150,
};
var buttonStyle = {
width:150,
backgroundColor: this.props.color
}
return (
<div style={fullBoxStyle}>
<span onClick={(e) => this.handleClick()}>
<ColorSquare color={this.props.color} />
<span style={{
isVisible: this.state.isVisible ? "true" : "false",
}}>
<HexDisplay color={this.props.color} />
</span>
</span>
</div>
);
}
}
ReactDOM.render(
<div class="colorRow">
<HexParent color="#ba2c9d" />
<HexParent color="#2cba90" />
<HexParent color="#2c9dba" />
</div>,
document.querySelector("#container")
);
</script>
When the object is created, it's a hexTextVis object. When you click, isVisible changes, but it's still a hexTextVis object and so the render doesn't change. You could either do something like:
<HexDisplay visibility={state.isVisible}/>
or
{state.isVisible ? <div/> : <HexDisplay />}
style={{
isVisible: this.state.isVisible ? "true" : "false",
}}
There isn't a css property with this name. Perhaps you meant to use visibility?
style={{
visibility: this.state.isVisible ? "visible" : "hidden"
}}
Try wrapping the span and and using a ternary operator to render the span element, based on if the condition of isVisible is equal to true, otherwise it should not return anything
{this.state.isVisible && <span><HexDisplay /></span>}

Loading multiple images simultaneously

I am trying to load images at the same time in React.js.
I tried a lot but still not able to figure out, how to do it.
This is the first thing, I tried to load images normally.
class MultipleImageExample extends React.Component {
constructor(props) {
super(props);
this.state = {
imageOneUrl: `https://picsum.photos/id/${parseInt(
Math.random() * 1000,
10
)}/400.jpg`,
imageTwoUrl: `https://picsum.photos/id/${parseInt(
Math.random() * 1000,
10
)}/400.jpg`,
imageOneLoaded: false,
imageTwoLoaded: false
};
}
render() {
return ( <
div >
<
h1 > Multiple Image Example < /h1> <
img src = {
this.state.imageOneUrl
}
style = {
{
objectFit: "cover",
width: "312px",
height: "216px"
}
}
alt = "image1" /
>
<
img src = {
this.state.imageTwoUrl
}
style = {
{
objectFit: "cover",
width: "312px",
height: "216px"
}
}
alt = "image2" /
>
<
/div>
);
}
}
ReactDOM.render( < MultipleImageExample / > , document.getElementById("root"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="root"></div>
This is the load event, I have attached to the img tag.
class MultipleImageExample extends React.Component {
constructor(props) {
super(props);
this.state = {
imageOneUrl: `https://picsum.photos/id/${parseInt(
Math.random() * 1000,
10
)}/400.jpg`,
imageTwoUrl: `https://picsum.photos/id/${parseInt(
Math.random() * 1000,
10
)}/400.jpg`,
imageOneLoaded: false,
imageTwoLoaded: false
};
}
handleImage1Load = e => {
this.setState({ ...this.state, imageOneLoaded: true });
};
handleImage2Load = e => {
this.setState({ ...this.state, imageTwoLoaded: true });
};
render() {
return (
<div>
<h1>Multiple Image Example</h1>
<img
src={this.state.imageOneUrl}
style={{ objectFit: "cover", width: "312px", height: "216px" }}
alt="image1"
onLoad={this.handleImage1Load}
/>
<img
src={this.state.imageTwoUrl}
style={{ objectFit: "cover", width: "312px", height: "216px" }}
alt="image2"
onLoad={this.handleImage2Load}
/>
</div>
);
}
}
ReactDOM.render(<MultipleImageExample />, document.getElementById("root"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="root"></div>
I am still confused, how I can show loaded images together.
Please help on this. This is the sandbox link : https://codesandbox.io/s/react-example-5f71p
You can use your second approach, and hide an image until the other has loaded, here's a working sandbox link (based on your link): https://codesandbox.io/s/react-example-3iblh
e.g. for the first image, you handle visibility based on state:
visiblity: this.state.imageTwoLoaded ? "visible" : "hidden"

How to make picture on focus in react-native

I have several pictures and onPress I want to make tapped picture bigger(on focus) make background dark with opacity like this.
If I will tap on this picture I wanna do roughly same thing but on mobile (react-native).
I believe you need to zoom the image from center and not from the top left. You can use this approach, and here is the pen for it: Codepen Link
class Profile extends React.Component {
constructor(props){
super(props);
this.state = {
height: '100%',
width: '100%',
flag: 0
};
}
render() {
var { pic } = this.props;
return (
<div>
<img src={pic} id="myImage" height={this.state.height} width={this.state.width} onClick={this.zoomHandler.bind(this)}/>
</div>
);
}
zoomHandler()
{
if(this.state.flag === 0)
{
document.getElementById("myImage").style.transform = "scale(2,2)";
this.setState({flag: 1});
}
else
{
document.getElementById("myImage").style.transform = "scale(1,1)";
this.setState({flag: 0});
}
}
}
React.render(
<Profile
pic="https://www.diariogol.com/uploads/s1/55/38/91/7/messi-leo-getafe-camp-nou_15_970x597.jpeg" />,
document.getElementById('app')
);
I have used states for height and weight, which can also be used for the zoom effect.
Use:
- Scale animation with Animated Component,
Example:
state = {
zoomImage: 1
}
zoomIn=()=>{
Animated.timing(this.state.zoomImage, {
toValue: 2,
duration: 2000,
userNativeDriver: true
})
}
render():
const animatedStyle = {
transform: [
{
scale: this.state.zoomImage
}
]
}
<TouchableOpacity onPress={() => this.zoomIn}>
<Image style={animatedStyle}/>
</TouchableOpacity>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
Refer: https://medium.com/react-native-training/react-native-animations-using-the-animated-api-ebe8e0669fae

React infinite scroll- double scrollbars showing- I only want the window scroll bar

Im trying to implement infinite scroll for React.js. Everything works fine, except I want to be able to use the window scrollbar, to activate the infinite scroll. The code at the moment, has 2 scrollbars( I only want one).
The code is from stackoverflow answered here, I read his complete answer, I tried setting the height to 100%, but it makes the infinite scroll not work. : Stackoverflow- answered by Aniket Jha, ( the longest answer with 4 upvotes)
Double scroll happens when I render this in this way:
<div>
<First />
<div ref="iScroll" style={{ height: "100vh", overflow: "auto"}}>
<ul>
{this.displayItems()}
</ul>
{this.state.loadingState ? <p className="loading"> loading More
Items..</p> : ""}
</div>
</div>
I have a Link to Codepen if this helps
class Layout extends React.Component {
constructor(props) {
super(props);
this.state = {
items: 30,
loadingState: false
};
}
componentDidMount() {
this.refs.iScroll.addEventListener("scroll", () => {
if (this.refs.iScroll.scrollTop + this.refs.iScroll.clientHeight >= this.refs.iScroll.scrollHeight - 20){
this.loadMoreItems();
}
});
}
displayItems() {
var items = [];
for (var i = 0; i < this.state.items; i++) {
items.push(<li key={i}>Item {i}</li>);
}
return items;
}
loadMoreItems() {
if(this.state.loadingState){
return;
}
this.setState({ loadingState: true });
setTimeout(() => {
this.setState({ items: this.state.items + 10, loadingState: false });
}, 1000);
}
render() {
return (<div>
<First />
<div ref="iScroll" style={{ height: "100vh", overflow: "auto"}}>
<ul>
{this.displayItems()}
</ul>
{this.state.loadingState ? <p className="loading"> loading More Items..</p> : ""}
</div>
</div>
);
}
}
class First extends React.Component {
constructor(props) {
super(props);
this.state = {
};
}
render() {
return (
<h1>Testing</h1>
)
}
}
ReactDOM.render(<Layout />, document.getElementById('example'));
If you don't want the second scrollbar to appear, you need to style the title and sibling div so that they fit in the available viewport.
In your codepen, you have height: '100%' for your scrolling div. This styles the div so that it doesn't need to scroll and infinite scroll therefore doesn't work.
If you style that div so that it takes up less than the height of the available viewport, and render enough items to fill it up, infinite scroll will work fine.
If you then style the title div combination so that they fit exactly into the available viewport space, you won't get a second scrollbar.
Below is an option you have to do this. What I've done is set the height of the scrolling div to be the viewport height (100vh) minus 100px. That's not precisely calculated, but what you want is to subtract the space required for the title from the size of the viewport.
This implementation works fine for me, and should for you as well.
class Layout extends React.Component {
constructor(props) {
super(props);
this.state = {
items: 30,
loadingState: false
};
}
componentDidMount() {
this.refs.iScroll.addEventListener("scroll", () => {
if (this.refs.iScroll.scrollTop + this.refs.iScroll.clientHeight >= this.refs.iScroll.scrollHeight - 20){
this.loadMoreItems();
}
});
}
displayItems() {
var items = [];
for (var i = 0; i < this.state.items; i++) {
items.push(<li key={i}>Item {i}</li>);
}
return items;
}
loadMoreItems() {
if(this.state.loadingState){
return;
}
this.setState({ loadingState: true });
setTimeout(() => {
this.setState({ items: this.state.items + 10, loadingState: false });
}, 1000);
}
render() {
return (<div>
<First />
<div ref="iScroll" style={{ height: "calc(100vh - 100px)", overflow: "auto"}}>
<ul>
{this.displayItems()}
</ul>
{this.state.loadingState ? <p className="loading"> loading More Items..</p> : ""}
</div>
</div>
);
}
}
class First extends React.Component {
constructor(props) {
super(props);
this.state = {
};
}
render() {
return (
<h1>Testing</h1>
)
}
}
ReactDOM.render(<Layout />, document.getElementById('example'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="example"></div>

How to append text to text area created in React JS?

I have the following code which creates a text area.
interface IReceiverProps {
receivedMessage: string;
topic: string;
}
export default class Receiver extends React.Component<IReceiverProps, {}> {
render() {
var textAreaStyle = {
width: 1300,
height: 450,
border: '3px solid #cccccc',
padding: '5px',
fontFamily: 'Tahoma, sans-serif',
overflow: 'auto',
marginLeft: '10px'
}
return (
<textarea style={textAreaStyle} value={this.props.receivedMessage}/>
);
}
}
This received message is passed by another component. How can I append the receivedMessage one below another in this text area? Any help would be much appreciated.
Use a state called textMessage.
constructor(props) {
super(props);
this.state = {
textMessage: props.receivedMessage
};
}
In componentWillReceiveProps, append to textMessage.
componentWillReceiveProps(nextProps) {
if (nextProps.receivedMessage !== this.props.receivedMessage) {
this.setState({
textMessage: `${this.state.textMessage}\n{nextProps.receivedMessage}`
});
}
}
Bind to textMessage.
<textarea style={textAreaStyle} value={this.state.textMessage} />

Categories