Trying to not fire a transition event when reloading the page - javascript

import { IconButton } from "#mui/material";
import React, { useState, useEffect } from "react";
import { Brightness4, Brightness7 } from "#mui/icons-material";
const ThemeChanger = () => {
const [themeState, setThemeState] = useState(false);
useEffect(() => {
const getTheme = localStorage.getItem("Theme");
if (getTheme === "dark") {
setThemeState(true);
} else {
}
}, []);
useEffect(() => {
if (themeState) {
localStorage.setItem("Theme", "dark");
document.body.classList.add("dark-mode");
} else {
localStorage.setItem("Theme", "light");
document.body.classList.remove("dark-mode");
}
}, [themeState]);
return (
<div>
<IconButton
className="icon-button"
style={{ marginTop: "16px" }}
onClick={() => {
setThemeState(!themeState);
document.body.classList.add("dark-light-toggle-transition");
}}
>
{themeState ? <Brightness4 /> : <Brightness7 />}
</IconButton>
</div>
);
};
export default ThemeChanger;
I am trying to make the former component to not fire the event of the transition that I have in "dark-mode" when I reload the page. The component is capable of toggling a dark mode.
I tried a bit of jQuery and the window.performance event but I could not make it work. I think the solution is not that hard but I am really loaded and my brain is not functioning anymore. Is there anyone who could help me?
P.S. I used a "preload" class with jQuery and set the class of the body into transition: none, however the problem is the useEffect as when the state is true it always adds the "dark-mode" class.
Thanks in advance!
EDIT: Actually I made it work. I just made a class called "dark-light-toggle-transition" which essentially is doing the work for me. I put it inside the jsx ThemeChanger component so it is only applied when I press the toggle button! If anyone needs more information, you can send me here!

Related

why is my if else statement returns true two times?

so I am new to React and I am trying to learn the basics. I got stuck at a point, where I try to show/hide an element on a page. The problem is that when I click Show details, it works, but Hide details must be clicked 2 times in order to do what its supposed to do.
Can you help me understand this?
import React, { useState } from 'react'
const Playground2 = () => {
let visible = false;
const [details, showDetails] = useState();
const [buttonText, changeButtonText] = useState("Show details");
const toggleVisibility = () => {
if (visible) {
showDetails("");
visible = false;
console.log(visible);
changeButtonText("Show details")
} else {
showDetails("Here are some details");
visible = true;
console.log(visible);
changeButtonText("Hide details");
}
}
return (
<>
<section>
<div className="container">
<h1>Visibility Toggle</h1>
<button onClick={toggleVisibility}>{buttonText}</button>
<p>{details}</p>
</div>
</section>
</>
)
}
export default Playground2
You should use the state in your condition. If you declare a variable like your visible one, this will be assigned on every render (every time you set the state with changeButtonText or showDetails. So every time will be set to false. You can simplify your component by doing:
import React, { useState } from 'react'
const Playground2 = () => {
const [visible, setVisible] = useState();
const toggleVisibility = () => {
setVisible(prevState => !prevState)
}
const buttonText = visible ? 'Hide details' : 'Show details'
const details = 'Here are some details'
return (
<>
<section>
<div className="container">
<h1>Visibility Toggle</h1>
<button onClick={toggleVisibility}>{buttonText}</button>
{visible && <p>{details}</p>}
</div>
</section>
</>
)
}
export default Playground2
Well it'd solve your problem if you turn visibility to state as well.
What I think happening is that when you click on button, the visibility variable is turned to false but component isn't refreshed. In order for component to get refreshed, there must be some change in state.
Maybe try that. That should do the trick.
Tip: Variables like loading, visibility, modal closed/open should be state variables.
Move let visible = false out of the component body and this will work as expected, since you are putting visible inside Component, every time the component updates false will be stored in visible.
let visible = false
const Playground 2 = () => {}

React collapsing div animation with CSS

I don't really understand why my component doesn't work. I want to create a component which expand/collapse when you click the button. It works fine, but I have a problem with the animation. When I click the button, website crashes. This is my component:
import { useState, useRef, React } from 'react'
const Collapsible = ({ desc, text }) => {
const [isOpen, setIsOpen] = useState(false);
const parentRef = useRef();
return (
<div className='city'>
<button className='toggle-btn' onClick={()=> {
setIsOpen(!isOpen);
}}>{text}</button>
{ isOpen &&
<div
className="city-info"
ref={parentRef}
style={isOpen ? {
height: parentRef.current.scrollHeight + "px",
}:{
height: "0px",
}}
>{desc}</div>}
</div>
)
}
export default Collapsible
And this is the error I get:
Uncaught TypeError: Cannot read properties of undefined (reading 'scrollHeight')
Why is it undefined? After a long time of trying to do it by myself, I gave up and I did a step-by-step with tutorial and it works great in the tutorial.

How to make the carousel scroll only when the cursor is on it, istead of anywhere on the windows?

I am using react-elastic-carousel in my app to scroll vertically between four components and each of them has some infos to show when scrolling on them. What I want to do is that the scrolling functionality should be happend only when the cursor is on the carousel and not everywhere on the page like is currently happening now. how I can make it possible any advices? Thanks a lot.
Here is what I did so far:
codesandbox.io/s/compassionate-leftpad-zzueys?file=/src/App.js
News.js:
import React, {useEffect, useRef } from "react";
import Carousel from "react-elastic-carousel";
import "./ news.css";
import {
Center,
Areas,
Place,
Others,
} from "./Contents";
const News = () => {
useEffect(() => {
document.title = "News";
});
const prevItemObject = "prev";
const nextItemObject = "next";
const slider = useRef(null);
function scroll(e) {
if (slider === null) return 0;
e.wheelDelta > 0
? slider.current.onNextStart(prevItemObject, nextItemObject)
: slider.current.onPrevStart();
}
useEffect(() => {
window.addEventListener("wheel", scroll, true);
return () => {
window.removeEventListener("wheel", scroll, false);
};
}, []);
return (
<div className="container">
<Carousel
onScroll={scroll}
verticalMode
itemsToShow={1}
enableSwipe={true}
ref={slider}
>
<Relevant />
<SearchByAreas />
<FindAPlaceToLive />
<FindTheRightRoomie />
</Carousel>
</div>
);
};
export default News;
App.js:
import React from "react";
import News from "./News";
const App = () => {
return (
<div>
<News />
</div>
);
};
export default App;
your wheel event listener is on window for now, it will listen all the wheel events on the window. Maybe you could add the listener on the slider ref like this :
slider.current.addEventListener("wheel", scroll, true);
Could you provide a codepen sample please ? It would be easier to test it ;)

onBlur / onClick conflict with CodeMirror2 in React

I have created multiple CodeMirror cells. OnBlur works fine, however if I click run button on the other cell, instead of firing run, it actually triggers onBlur and then I need to click mouse again to trigger run. Ideally both of these events should be fired when run button is clicked.
I have seen that the issue is with the order of precedence for these two events and one of the proposed solutions was to add ref attribute to code mirror like this ref = {cell => this.cell = cell} and then in the other handler which is related to run button do this.cell.focus() or in some similar way.
Unfortunately I am not even able to access ref attribute for CodeMirror2 so I can't test it. I will paste both of these components and any suggestion is appreciated.
To summarize: The issue is that onBlur shadows onClick, so run button needs to be clicked twice. I want to be able to click run button and that both onBlur and handleRunClick fire.
import React, { Component } from "react";
import { Controlled as CodeMirror } from "react-codemirror2";
import CellResults from "./CellResults";
import CellToolbar from "../Shared/CellToolbar";
import AddCellButton from "../Shared/AddCellButton";
import "codemirror/lib/codemirror.css";
import "codemirror/theme/darcula.css";
import "codemirror/mode/javascript/javascript.js";
import "codemirror/mode/ruby/ruby.js";
import "codemirror/mode/python/python.js";
class CodeCell extends Component {
state = {
code: this.props.cell.code
};
handleChange = value => {
this.setState({ code: value });
};
handleBlur = () => {
this.props.onUpdateCodeState(this.state.code, this.props.cellIndex);
if (this.props.language === "Markdown") {
this.props.toggleRender(this.props.cellIndex);
}
};
render() {
const cell = this.props.cell;
const cellOptions = {
mode: cell.type.toLowerCase(),
theme: "darcula",
lineNumbers: true,
showCursorWhenSelecting: true
};
return (
<div>
<div className="add-cell-container">
<AddCellButton
className="add-cell-btn"
onClick={this.props.onAddClick}
cellIndex={this.props.cellIndex}
/>
</div>
<CellToolbar
cellIndex={this.props.cellIndex}
onDeleteClick={this.props.onDeleteClick}
language={cell.type}
onLanguageChange={this.props.onLanguageChange}
rendered={cell.rendered}
onRunClick={this.props.onRunClick}
/>
<CodeMirror
value={this.state.code}
options={cellOptions}
onBeforeChange={(editor, data, value) => {
this.handleChange(value);
}}
onBlur={this.handleBlur}
/>
{cell.type !== "Markdown" ? (
<CellResults language={cell.type} results={cell.results} />
) : null}
</div>
);
}
}
export default CodeCell;
import React from "react";
import Button from "react-bootstrap/Button";
class RunCellButton extends React.Component {
handleRunClick = () => {
this.props.onClick(this.props.cellIndex);
};
render () {
return (
<Button
className="run-button"
onClick={this.handleRunClick}
variant="secondary"
size="sm"
>
<span>►</span>
</Button>
);
}
};
export default RunCellButton;
Below is the similar problem with Adding Cell. When I trigger click event it fires, the state of show is changed to true but if I log it on line 36 it is still false. I am triggering click event from a different component, again due to this obBlue shadowing everything else so every button needs to be clicked twice.
import React, { Component } from "react";
import SplitButton from "react-bootstrap/SplitButton";
import * as constants from "../../Constants/constants";
import DropdownButton from "react-bootstrap/DropdownButton";
import Dropdown from "react-bootstrap/Dropdown";
class AddCellButton extends Component {
state = {
show: false
}
handleSelectCellType = language => {
this.props.onClick(this.props.cellIndex, language);
};
handleToggle = () => {
this.setState((prevState) => {
return {
show: !prevState["show"]
}
})
}
render() {
const dropDownItems = constants.LANGUAGES.map(language => {
return (
<Dropdown.Item
as="button"
value={language}
key={language}
eventKey={language}
>
{language}
</Dropdown.Item>
);
});
console.log("state of show " + this.state.show)
return (
<DropdownButton
show={this.state.show}
onToggle={this.handleToggle}
className="add-cell-btn"
variant="secondary"
id="dropdown-basic-button"
title={<span>+</span>}
size="sm"
onSelect={this.handleSelectCellType}
>
{dropDownItems}
</DropdownButton>
);
}
}
export default AddCellButton;

React-bootstrap styling showing up before finished api call

I am making a small application in React that fetches a random image using Axios. I am using React-bootstrap to style the image, however a small white box is displayed for half of a second before the image is done loading. How can I resolve this?
This is my code:
import React, { Component } from 'react';
import axios from 'axios';
import { Link } from 'react-router-dom';
import { Image, Button } from 'react-bootstrap';
const ROOT_URL = 'myurl'
export default class WhatDog extends Component {
constructor(props){
super(props);
this.state = { randomImg: '' };
}
componentDidMount(){
axios.get(ROOT_URL)
.then(res => {
const data = res.data.message
this.setState({ randomImg: data })
})
}
renderImage(){
return(
<div>
<Image src={this.state.randomImg} className="img" thumbnail/>
<Link to="/">
<Button bsStyle="danger" bsSize="large">Go back</Button>
</Link>
</div>
)
}
render() {
return (
<div className="App">
{
(this.state.randomImg === '')
? <div>
<h1>Loading...</h1>
</div>
: <div>
{this.renderImage()}
</div>
}
</div>
);
}
}
The browser will fire the onLoad event, after the image has been, you name it.. loaded so before that, set the visibility to hidden.. NOT display: none ! Because display: none will also prevent the loading.
The solution might look something like this
<Image
src={this.state.randomImg}
style={!this.state.imgVisible ? {visibility: 'hidden'} : {}}
onLoad={() => this.setState({ imgVisible: true })}
/>
Note: This is using inline styles and arrow functions, which is not best, but for simplicity of the demo its enough, you could also you a className instead, its up to you ;)
You got the idea...

Categories

Resources