Display object datas in JSX - reactjs

I have this Object in my state :
console.log(state)
I created a component to render a card for each entry in this object (which has under object)
I have tried everything, but I always get an error. Here is my last attempt :
import { useState } from "react"
export default function Categories(props: any) {
const [listOfCategories, setListOfCategories] = useState(props.datas.categories)
console.log(listOfCategories)
return (
<>
{listOfCategories.map(category => {
return (
<div key={category} className="relative flex flex-wrap h-96 my-20">
<div className="absolute right-0 top-0 h-full">
<img className="rounded-lg max-w-full h-96" src="https://double-you-design.fr/wp-content/uploads/2016/04/dummy-post-horisontal.jpg" alt="" />
</div>
<div className="absolute -bottom-10 bg-white rounded-lg shadow-lg w-7/12 h-48 p-8">
<p key={category}>{category}</p>
</div>
</div>
)
})
}
</>
)
}
the error is : listOfCategories.map is not a function.
My question is : What is the simplest method to do this ?
Do you have a recommandation, or an example ?
I am working with TypeScript.
Thank you very much !

You can't use .map on an object because it is a method of Array.
You could do it with Object.keys like so:
import { useState } from "react"
export default function Categories(props: any) {
const [listOfCategories, setListOfCategories] = useState(props.datas.categories)
console.log(listOfCategories)
return (
<>
{Object.keys(listOfCategories).map((key, ind) => {
return (
<div key={ind} className="relative flex flex-wrap h-96 my-20">
<div className="absolute right-0 top-0 h-full">
<img className="rounded-lg max-w-full h-96" src="https://double-you-design.fr/wp-content/uploads/2016/04/dummy-post-horisontal.jpg" alt="" />
</div>
<div className="absolute -bottom-10 bg-white rounded-lg shadow-lg w-7/12 h-48 p-8">
<p key={ind}>{listOfCategories[key].category}</p>
</div>
</div>
)
})
}
</>
)
}
Here is a simple runnable example to illustrate:
var obby = { a: { category: 'Estimation' }, b: { category: 'Prospection' } }
const categories = Object.keys(obby).map(key => obby[key].category)
console.log(categories)
Another option would be to change your data structure so that you have an array of objects instead of an object of objects - if you have control over that data structure. If not, you could first convert the object to an array.
const obby = { estimate: { category: 'Estimation' }, prospecting: { category: 'Prospection' } }
const arr = Object.values(obby)
const categories = arr.map(val => val.category)
console.log(categories)
Above method in your code:
import { useState } from "react"
export default function Categories(props: any) {
const [listOfCategories, setListOfCategories] = useState(props.datas.categories)
const listOfCategoriesArray = Object.values(listOfCategories)
return (
<>
{listOfCategoriesArray.map((item, ind) => {
return (
<div key={ind} className="relative flex flex-wrap h-96 my-20">
<div className="absolute right-0 top-0 h-full">
<img className="rounded-lg max-w-full h-96" src="https://double-you-design.fr/wp-content/uploads/2016/04/dummy-post-horisontal.jpg" alt="" />
</div>
<div className="absolute -bottom-10 bg-white rounded-lg shadow-lg w-7/12 h-48 p-8">
<p key={ind}>{item.category}</p>
</div>
</div>
)
})
}
</>
)
}

Related

state does not update using useContext even if works in another app

Im trying to build an application where I am using useState and then passing it using context. But whenever I try onCLick increment it doesnot work. state update does not happen.
Here is the state fucntion code,
import { createContext, useReducer, useState } from "react";
import { DOG_ACTION } from "../utilities/app-utilities";
import { dogList } from "../utilities/dogList";
export const DogContext = createContext();
export const DogProvider = ({ children }) => {
const [dogs, setDogs] = useState(dogList);
const dogActions = (action, payload) => {
switch (action) {
case DOG_ACTION.ADD_DOG: {
setDogs((value) => {
value.map((item) => {
if (item.id == payload) item.amount += 1;
});
return value;
});
return 0;
}
case DOG_ACTION.MINUS_DOG: {
setDogs((prev) => {
return prev.map((item) => {
if (item.id == payload) {
item.amount -= 1;
console.log(item.amount);
}
return item;
});
});
console.log("MINUS");
return 0;
}
default:
return 0;
}
};
return (
<DogContext.Provider value={{ dogs, dogActions }}>
{children}
</DogContext.Provider>
);
};
Here is the App,js,
import { LoggedInProvider } from "./hooks/logged-in-hook";
import { OverLayProvider } from "./hooks/overlay-hook";
import { Hero } from "./pages/Hero";
import { DogProvider } from "./hooks/dog-hook";
function App() {
// console.log("App Level- DIST");
return (
<DogProvider>
<LoggedInProvider>
<OverLayProvider>
<div className="App">
<Hero />
</div>
</OverLayProvider>
</LoggedInProvider>
</DogProvider>
);
}
export default App;
And lastly here is the element where I need to use onCLick,
import React, { useContext } from "react";
import { DogContext } from "../hooks/dog-hook";
import { DOG_ACTION } from "../utilities/app-utilities";
export const DogCard = ({ name, breed, speciality, amount, image, id }) => {
const action = useContext(DogContext).dogActions;
return (
<div className="flex flex-col items-start rounded-lg bg-slate-900 p-6 shadow-xl">
<div className="flex w-full flex-row items-center justify-between">
<button
onClick={() => {
action(DOG_ACTION.MINUS_DOG, id);
}}
className="flex flex-row items-center space-x-2 rounded-full bg-slate-700 px-4 py-2 text-white hover:bg-slate-800">
<img
src="https://cdn-icons-png.flaticon.com/512/9513/9513736.png"
alt="paw"
className="w-4"
/>
<p className="text-sm">Add to Cart</p>
</button>
<div className="rounded-xl bg-slate-700 px-4 py-2 text-sm text-white">
🛒:<span className="text-orange-500"> {amount}</span>
</div>
</div>
<div className="mt-8 flex w-full flex-row space-x-10">
<div>
<img
src={require(`./../images/dog-images/${image}.jpg`)}
alt="sample"
className="h-fit w-32 rounded-l-lg"
/>
</div>
<div className="flex flex-col text-white">
<h3 className="pb-8 text-3xl font-bold text-slate-200">{name}</h3>
<p>
<span className="text-gray-400">Breed:</span> {breed}
</p>
<p>
<span className="text-gray-400">Origin:</span> {speciality}
</p>
</div>
</div>
</div>
);
};
It works when I created a dummy array to taste in some other app. But not with this one. Even though everything is similar.

How do i fix the error when updating state

In my application, I am making a request to the backend with redux-thunk and fetching the pricingData. I keep the items in the pricingData first 10 items in the items variable by passing certain operations. I want to update the questionRange variable with the first items[0] value. But using setQuestionRange immediately causes infinite loop.
So i tried these:
if i have an array with multiple elements, update the setQuestionRange. But but the error still persisted
React limits the number of renders to prevent an infinite loop.
if (items.length > 0) {
setQuestionRange(items[0])
}
I used useEffect. But this caused another error:
Warning: Maximum update depth exceeded. This can happen when a component calls setState inside useEffect, but useEffect either doesn't have a dependency array, or one of the dependencies changes on every render.
useEffect(() => {
if (items) {
setQuestionRange(items[0])
}
}, [items])
How can i solve this? Here is my component:
import { Container } from '#/components/Container'
import Filters from './Filters'
import Cost from './Filters/Cost'
import { useState, useEffect } from 'react'
import { useDispatch, useSelector } from 'react-redux'
import { getAllPricing } from '#/store/actions/pricingAction'
function SwirlyDoodle({ className }) {
return (
<svg
aria-hidden="true"
viewBox="0 0 281 40"
className={className}
preserveAspectRatio="none"
>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M240.172 22.994c-8.007 1.246-15.477 2.23-31.26 4.114-18.506 2.21-26.323 2.977-34.487 3.386-2.971.149-3.727.324-6.566 1.523-15.124 6.388-43.775 9.404-69.425 7.31-26.207-2.14-50.986-7.103-78-15.624C10.912 20.7.988 16.143.734 14.657c-.066-.381.043-.344 1.324.456 10.423 6.506 49.649 16.322 77.8 19.468 23.708 2.65 38.249 2.95 55.821 1.156 9.407-.962 24.451-3.773 25.101-4.692.074-.104.053-.155-.058-.135-1.062.195-13.863-.271-18.848-.687-16.681-1.389-28.722-4.345-38.142-9.364-15.294-8.15-7.298-19.232 14.802-20.514 16.095-.934 32.793 1.517 47.423 6.96 13.524 5.033 17.942 12.326 11.463 18.922l-.859.874.697-.006c2.681-.026 15.304-1.302 29.208-2.953 25.845-3.07 35.659-4.519 54.027-7.978 9.863-1.858 11.021-2.048 13.055-2.145a61.901 61.901 0 0 0 4.506-.417c1.891-.259 2.151-.267 1.543-.047-.402.145-2.33.913-4.285 1.707-4.635 1.882-5.202 2.07-8.736 2.903-3.414.805-19.773 3.797-26.404 4.829Zm40.321-9.93c.1-.066.231-.085.29-.041.059.043-.024.096-.183.119-.177.024-.219-.007-.107-.079ZM172.299 26.22c9.364-6.058 5.161-12.039-12.304-17.51-11.656-3.653-23.145-5.47-35.243-5.576-22.552-.198-33.577 7.462-21.321 14.814 12.012 7.205 32.994 10.557 61.531 9.831 4.563-.116 5.372-.288 7.337-1.559Z"
/>
</svg>
)
}
export function Pricing() {
const [fieldSelectionMultipliers, setFieldSelectionMultipliers] = useState(0)
const [questionRange, setQuestionRange] = useState(0)
const [audienceCount, setAudienceCount] = useState(100)
const [totalCost, setTotalCost] = useState(null)
const dispatch = useDispatch()
const { pricingData } = useSelector((state) => state.pricing.getPricingData)
const isPricingDataEmpty = Object.keys(pricingData).length === 0
const fieldsData =
!isPricingDataEmpty &&
pricingData.items.filter((item) => item.content_object.content_type === 27)
const comboboxData =
!isPricingDataEmpty &&
pricingData.items.filter((data) => data.content_object.content_type === 41)
let items = !comboboxData
? []
: comboboxData.map((item) => ({
id: item.content_object.nanoid,
name: item.content_object.name,
multiplier: item.multiplier,
}))
const selectedFields = JSON.parse(JSON.stringify(fieldsData))
const exchangeRate = !isPricingDataEmpty && +pricingData.exchange_rate
const basePrice = !isPricingDataEmpty && +pricingData.base_price
const calculateCost = () => {
let numberFormat = Intl.NumberFormat('en-US')
let rate = exchangeRate * basePrice
let questionRangeMultiplier = questionRange ? questionRange.multiplier : 0
let total_multiplier =
(+fieldSelectionMultipliers + +questionRangeMultiplier) * rate
let total = Math.round(total_multiplier * audienceCount * 100) / 100
setTotalCost(numberFormat.format(total))
}
useEffect(() => {
calculateCost()
}, [fieldSelectionMultipliers, questionRange, exchangeRate, audienceCount])
useEffect(() => {
dispatch(getAllPricing())
}, [])
// if (items) {
// setQuestionRange(items[0])
// }
// useEffect(() => {
// if (items) {
// setQuestionRange(items[0])
// }
// }, [items])
return (
<section
id="pricing"
aria-label="Pricing"
className="bg-slate-900 py-20 sm:py-32"
>
<Container>
<div className="bg-slate-900">
<div className="mx-auto max-w-7xl px-4 sm:px-6 lg:px-8">
<div className="text-center">
<h2 className="font-display text-3xl tracking-tight text-white sm:text-4xl">
<span className="relative whitespace-nowrap">
<SwirlyDoodle className="absolute top-1/2 left-0 h-[1em] w-full fill-indigo-400" />
<span className="relative">Net fiyatlama,</span>
</span>{' '}
sometext
</h2>
<p className="my-5 text-lg text-slate-400">
sometext
</p>
</div>
</div>
<div className="relative">
<div className="absolute inset-0 h-1/2 bg-slate-900" />
<div className="relative mx-auto max-w-7xl px-4 sm:px-6 lg:px-8">
<div className="mx-auto max-w-lg overflow-hidden rounded-lg shadow-lg lg:flex lg:max-w-none">
<div className="flex-1 bg-white px-6 py-8 lg:p-12">
<h3 className="text-2xl font-bold text-gray-900 sm:text-3xl sm:tracking-tight">
sometext
</h3>
<div className="mt-8">
<div className="flex items-center">
<h4 className="flex-shrink-0 bg-white pr-4 text-base font-semibold text-indigo-600">
sometext
</h4>
<div className="flex-1 border-t-2 border-gray-200" />
</div>
{selectedFields && (
<Filters
selectedFields={selectedFields}
fieldSelectionMultipliers={fieldSelectionMultipliers}
setFieldSelectionMultipliers={
setFieldSelectionMultipliers
}
/>
)}
</div>
</div>
{comboboxData && (
<Cost
items={items}
questionRange={questionRange}
setQuestionRange={setQuestionRange}
audienceCount={audienceCount}
setAudienceCount={setAudienceCount}
totalCost={totalCost}
/>
)}
</div>
</div>
</div>
</div>
</Container>
</section>
)
}

Lazy loading element in typescript hook not working

I've implemented a lazy loading hook, but for some reason the carousel component is not loading at all. I've got it from here: https://betterprogramming.pub/lazy-loading-in-next-js-simplified-435681afb18a
This is my child that I want to render when it's in view:
import { useRef } from "react";
import Carousel from "../components/carousel";
import useOnScreen from "../hooks/useOnScreen";
// home page
function HomePage() {
const carouselRef = useRef();
const carouselRefValue = useOnScreen(carouselRef);
return (
<div className="snap-y">
{/* 1 */}
<div className="flex justify-center items-start relative min-h-[calc(100vh_-_5rem)] bg-black snap-start ">
{/* Cone */}
<div className="absolute w-full max-w-full overflow-hidden min-w-fit cone animate-wiggle"></div>
<div className="grid justify-center grid-cols-4 max-w-7xl">
//Content
</div>
{/* 2 */}
<div className="z-20 pb-4 bg-black snap-start" ref={carouselRef.current}>
{carouselRefValue && <Carousel />}
</div>
{/* 3 */}
<div className="flex items-start justify-center py-32 min-h-fit bg-slate-50 snap-start">
//More content
</div>
);
}
export default HomePage;
useOnScreen hook:
import { useState, useEffect } from "react";
const useOnScreen = (ref: any) => {
const [isIntersecting, setIntersecting] = useState(false);
useEffect(() => {
const observer = new IntersectionObserver(([entry]) => setIntersecting(entry.isIntersecting));
if (ref.current) {
observer.observe(ref.current);
}
}, []);
return isIntersecting;
};
export default useOnScreen;
Edit: Needed to add const carouselRef = useRef() as React.MutableRefObject<HTMLInputElement>; paired with #asynts's answer.
This is incorrect:
<div className="z-20 pb-4 bg-black snap-start" ref={carouselRef.current}></div>
it should be:
<div className="z-20 pb-4 bg-black snap-start" ref={carouselRef}></div>

react js: infinite page rendering issue

So I have a page in react that is constantly rendering , say for eg. when I console log I can see that getting logged infinitely in a loop. is it some hook on some inner components that is getting rendered constantly I can't figure out
When i comment out
<CartContainer line_items = {line_items} />
it still doesnt solve the issue.
could useCartState() context be the issue?
Below is the page
import React, {useEffect} from "react"
import { CartContainer, NavigationBar } from "../components"
import {useRouter} from 'next/router'
import { useCartState } from "../context/Cart"
import { QuestionMarkCircleIcon } from '#heroicons/react/solid'
const getPaymentAPIStatus = async () =>
{
const response = await fetch("https://api.nowpayments.io/v1/status")
const data = await response.json()
}
const CartPage = () => {
const router = useRouter();
const {line_items, subtotal, total_items} = useCartState() // to get cart details --anaya
const isEmpty = line_items.length === 0
if(isEmpty)
return(
<div>
<NavigationBar/>
<p>Your cart is empty. Please add some items</p>
</div>
)
else {
return(
<div>
<NavigationBar/>
<div className="bg-white">
<div className="max-w-2xl mx-auto pt-16 pb-24 px-4 sm:px-6 lg:max-w-7xl lg:px-8">
<h1 className="text-3xl font-extrabold tracking-tight text-gray-900 sm:text-4xl">Shopping Cart</h1>
<form className="mt-12 lg:grid lg:grid-cols-12 lg:gap-x-12 lg:items-start xl:gap-x-16">
<section aria-labelledby="cart-heading" className="lg:col-span-7">
<h2 id="cart-heading" className="sr-only">
Items in your shopping cart
</h2>
<CartContainer line_items = {line_items} />
</section>
{/* Order summary */}
<section
aria-labelledby="summary-heading"
className="mt-16 bg-gray-50 rounded-lg px-4 py-6 sm:p-6 lg:p-8 lg:mt-0 lg:col-span-5"
>
<h2 id="summary-heading" className="text-lg font-medium text-gray-900">
Order summary
</h2>
<dl className="mt-6 space-y-4">
<div className="flex items-center justify-between">
<dt className="text-sm text-gray-600">Subtotal</dt>
<dd className="text-sm font-medium text-gray-900">{subtotal.formatted_with_symbol}</dd>
</div>
<div className="border-t border-gray-200 pt-4 flex items-center justify-between">
<dt className="flex items-center text-sm text-gray-600">
<span>Shipping estimate</span>
<a href="#" className="ml-2 flex-shrink-0 text-gray-400 hover:text-gray-500">
<span className="sr-only">Learn more about how shipping is calculated</span>
<QuestionMarkCircleIcon className="h-5 w-5" aria-hidden="true" />
</a>
</dt>
<dd className="text-sm font-medium text-gray-900">Free</dd>
</div>
<div className="border-t border-gray-200 pt-4 flex items-center justify-between">
<dt className="text-base font-medium text-gray-900">Order total</dt>
<dd className="text-base font-medium text-gray-900">{subtotal.formatted_with_symbol}</dd>
</div>
</dl>
<div className="mt-6">
<button
type="submit"
className="w-full bg-indigo-600 border border-transparent rounded-md shadow-sm py-3 px-4 text-base font-medium text-white hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-offset-gray-50 focus:ring-indigo-500"
>
Checkout
</button>
</div>
<div className="mt-6 text-sm text-center">
<p>
or{' '}
<a href ={`${router.basePath}/ChooseProduct`} className="text-indigo-600 font-medium hover:text-indigo-500">
Continue Designing<span aria-hidden="true"> →</span>
</a>
</p>
</div>
</section>
</form>
</div>
</div>
</div>
)
}
}
export default CartPage
How do i solve this?
Thanks in advance!
Adding useCartState as requested
import {createContext, useEffect, useContext, useReducer} from 'react'
import {commerce} from '../../lib/commerce'
//need to correct this file to be a tsx file in the future
//Provides a context for Cart to be used in every page
const CartStateContext = createContext()
const CartDispatchContext = createContext()
const SET_CART = "SET_CART"
const initialState = {
total_items: 0,
total_unique_items: 0,
subtotal:[],
line_items: [{}]
}
const reducer = (state,action) => {
switch(action.type){
case SET_CART:
return { ...state, ...action.payload }
default:
throw new Error(`Unknown action: ${action.type}` )
}
}
export const CartProvider = ({children}) => {
const [state, dispatch] = useReducer(reducer, initialState)
const setCart = (payload) => dispatch({type: SET_CART, payload})
useEffect(() => {
getCart()
},[state]) // Getting the page to be rendered whenever the cart objects are changed
const getCart = async() => {
try {
const cart = await commerce.cart.retrieve()
setCart(cart)
} catch (error){
console.log("error")
}
}
return (
<CartDispatchContext.Provider value = {{setCart}}>
<CartStateContext.Provider value = {state}>
{children}
</CartStateContext.Provider>
</CartDispatchContext.Provider>
)
}
export const useCartState = () => useContext (CartStateContext)
export const useCartDispatch = () => useContext (CartDispatchContext)
The problem here is that you have a useEffect with state as a dependency, meaning that every time the state value is altered, the getCart function gets called.
Meanwhile, getCart sets the state within it.
Therefor, it creates a cycle where getCart sets the state, the useEffect callback runs as a result, getCart gets called again, sets the state again, and so on.
The bottom line is that you can not set the state inside of a function and call that function every time the state value is altered.

Reactjs setInterval with scroll only trigger once

I have auto scroll function and scroll will start when user click the function as follow.
It is scroll 50px to y axis once when user click play button. But it is only scroll once even thought I have added interval. Interval is working because I saw the "scrolling" console.log is increasing. But scroll is not scrolling again.
May I know why scroll is not move again?
import React, { useState, useEffect, useRef } from "react";
import { useParams, NavLink } from "react-router-dom";
import { useQuery } from "#apollo/client";
import { getTrack, getTrackVariable } from "../../gql/track";
import ChordSheetJS from "chordsheetjs";
import {
YoutubeIcon,
FacebookIcon,
PlayIcon,
PauseIcon,
} from "../../assets/icons/svg_icons";
import { SettingIcon } from "../../assets/icons/svg_icons";
import paths from "../../routes/paths";
import { FacebookShareButton } from "react-share";
import GoTop from "../../components/go_top";
const TrackPage = () => {
const intervalId = useRef(null);
const { trackId } = useParams();
const [track, setTrack] = useState();
const [collapse, setCollapse] = useState(true);
const [play, setPlay] = useState(false);
const [speed, setSpeed] = useState(1);
const { loading, error, data } = useQuery(getTrack, {
variables: getTrackVariable(trackId),
});
const trackRef = useRef();
useEffect(() => {
if (!loading && !error) {
setTrack(data?.track);
}
}, [loading, error, data]);
const getChordSheet = (value) => {
const parser = new ChordSheetJS.ChordProParser();
const song = parser.parse(value);
const formatter = new ChordSheetJS.HtmlTableFormatter();
const chordSheet = formatter.format(song);
return chordSheet;
};
const handleError = (e) => {
e.target.onerror = null;
e.target.src = Monk;
};
const handleMenuCollapse = (e) => {
e.preventDefault();
setCollapse(!collapse);
};
const handleSpeedUp = () => {
setSpeed(speed + 1);
};
const handleSpeedDown = () => {
setSpeed(speed - 1);
};
const handleScroll = () => {
setPlay(!play);
if (play) {
console.log("stop");
clearInterval(intervalId.current);
} else {
let delayInMs = 100;
const onScrollStep = () => {
document.getElementById("content").scroll(0,50);
console.log("srolling")
};
intervalId.current = setInterval(onScrollStep, delayInMs);
console.log("play");
}
};
return (
<>
<div id="setting">
{/** the big div */}
<div
className={` w-36 h-56 bg-primary absolute top-[calc((100vh-384px)/2)] ${
collapse ? "hidden" : "right-0"
} " bg-primary rounded-b-lg items-center justify-center`}
>
<div>
<div className="items-center justify-center mt-5">
<div className="flex text-xs items-center justify-center ">
<span className=" text-sm text-white">Scroll</span>
</div>
<div className="flex text-xs pt-0 mt-0 items-center justify-center ">
<button
className="px-2 btn-sm flex w-20 items-center bg-transparent hover:bg-accent border text-white font-semibold hover:text-white border-white hover:border-transparent rounded "
onClick={handleScroll}
>
{play ? (
<PauseIcon className="text-white mr-2" />
) : (
<PlayIcon className="text-white mr-2" />
)}
{play ? <span>Pause</span> : <span>Play</span>}
</button>
</div>
<div className="flex text-xs items-center justify-center mt-2">
<button
className="w-auto bg-transparent mr-2 hover:bg-accent text-white font-semibold hover:text-white py-1 px-2 border border-white hover:border-transparent rounded"
onClick={handleSpeedDown}
>
-1
</button>
<button
className="w-auto bg-transparent ml-2 hover:bg-accent text-white font-semibold hover:text-white py-1 px-2 border border-white hover:border-transparent rounded"
onClick={handleSpeedUp}
>
+1
</button>
</div>
</div>
</div>
</div>
{/** the icon div */}
<div
className={`flex w-12 absolute top-[calc((100vh-384px)/2)] h-12 bg-primary
${collapse ? "animate-pulse right-0" : "right-36"}
cursor-pointer bg-primary rounded-l-lg items-center justify-center`}
onClick={handleMenuCollapse}
>
{/* <div className="w-5 h-5 bg-white rounded-full " /> */}
<SettingIcon />
</div>
</div>
<div id="track" ref={trackRef}>
<div className="flex flex-col w-full py-1 my-1 items-center bg-gray-50">
<div className="relative my-6 mx-auto md:min-w-[60%] max-h-full">
{track ? (
<div className="w-full">
<pre
className="px-5 textarea"
dangerouslySetInnerHTML={{
__html: getChordSheet(track.lyric),
}}
/>
</div>
) : (
<div></div>
)}
</div>
</div>
</div>
</>
);
};
export default TrackPage;
app.jsx
import React, { useState, useEffect } from "react";
import Header from "./components/header";
import SideMenu from "./components/side_menu";
import AppRoutes from "./routes";
import withUser from "./hocs/with_user";
import { isMobile } from "react-device-detect";
import { useLocation } from "react-router-dom";
import { AuthProvider, setAccessToken } from "./auth/auth_provider";
import { Toaster } from "react-hot-toast";
import AppContext from "./components/app_context";
import "./i18n";
import "./App.css";
function App(props) {
const [collapse, setCollapse] = useState(isMobile);
const [sideBarFull] = useState(true);
const location = useLocation();
const IsNormalPage = () => {
const blankPages = ["/login"];
for (let i = 0; i < blankPages.length; i++) {
if (location.pathname.startsWith(blankPages[i])) return
false;
}
return true;
};
useEffect(() => {
if (props.user) setAccessToken(props.user.t);
}, []);
const PageHeader = () => {
return (
<div className="h-[72px] w-full flex items-center align-middle justify-center bg-neutral shadow">
<div className="w-full text-center">
<Header />
</div>
</div>
);
};
return (
<AuthProvider user={props.user}>
<AppContext.Provider
value={{
collapse: collapse,
setCollapse: setCollapse,
}}
>
<div className="relative w-full min-h-screen h-full">
<div className="flex flex-row min-h-screen">
<div className="w-auto z-0 ">
<div className="flex-1 w-full max-h-screen mx-auto text-lg h-full shadow-lg bg-white overflow-y-auto">
{IsNormalPage() && <SideMenu showFullMenu={sideBarFull} />}
</div>
</div>
<div className="w-full max-h-screen flex flex-col z-10">
{IsNormalPage() && <PageHeader />}
<div id="content" className="flex-1 w-full max-h-screen mx-auto text-lg h-full shadow-lg bg-white overflow-y-auto">
<Toaster />
<AppRoutes />
</div>
</div>
</div>
</div>
</AppContext.Provider>
</AuthProvider>
);
}
export default withUser(App);
I think because you are toggling the play state in your component
setPlay(!play);
Are you trying to scroll to a specific div or just scroll for 50 px in the direction of y-axis? there are two approaches, you can use window or Refs.
an example using the refs to scroll to a specific node in the dom
const ScrollDemo = () => {
const myRef = useRef(null)
const executeScroll = () => { myRef.current.scrollIntoView()}
return (
<div>
<div ref={myRef}>Element to scroll to</div>
<button onClick={executeScroll}> Click to scroll </button>
<div/>
)
}
or if you just want to just scroll 50 pixel in the direction of y-axis
const scrollToTop = () => {
window.scrollTo(0,50);
};
return (
<button onClick={scrollToTop}>
Go down 50 px!
</button>
);
window.scrollTo is only working with html body. document.getElementById is only working overflow div.
useEffect(() => {
if (play) {
const onScrollStep = () => {
var e = document.getElementById("content");
if (e.scrollHeight - e.scrollTop === e.clientHeight) {
clearInterval(intervalId.current);
setPlay(!play);
return;
}
e.scroll(0, e.scrollTop + speed);
};
intervalId.current = setInterval(onScrollStep, delayInMs);
} else {
clearInterval(intervalId.current);
}
},[play, speed])

Resources