how can i get the text from within the div? - javascript

const questions = (props) => {
const { question, options, id } = props.quiz;
const selected = (e) => {
e.target.children[0].checked = true;
console.log(e.target);
};
return (
<div className="bg-gray-200 p-6 m-10 rounded-md">
<div className="font-bold text-xl text-slate-600">{question}</div>
<div className="grid grid-cols-2 mt-4">
{options.map((option) => (
<div className="border-2 border-solid border-gray-400 rounded text-gray-500 m-1">
<div className="flex cursor-pointer p-3" id={id} onClick={selected}>
<input type="radio" className="mr-2" name="name" />
{option}
</div>
</div>
))}
</div>
</div>
);
};
export default questions;
if console.log(e.target) is done in the selected function return the Div. How can I access the text of the Div within the selected function?

You can access the text of the Div within the selected function by using the .textContent property on the e.target object. This will return the text content of the Div that was clicked.
const selected = (e) => {
e.target.children[0].checked = true;
console.log(e.target.textContent);
};

Related

send values ​from the child component to the parent and sum the result

I'm using useFieldArray from react-hook-form to replicate my requirements component, but I need to get the return value from the requirementValueCalc function and pass it to my form component. In it I want to sum the values ​​of each inserted field. Can someone help me?
enter image description here
My form - parent component:
const ThirdPage: ForwardRefRenderFunction<
HTMLSelectElement,
ThirdPageProps
> = ({
formProps: {
register,
formState: { errors },
control,
setValue,
setFocus,
},
formData,
secondPageData,
}) => {
const {
dealId,
object,
contractPeriod,
paymentMethodId,
dueDay,
totalHours,
totalValue,
} = formData[0];
const [currentIndex, setCurrentIndex] = useState<number>(0);
const [requirements, setRequirements] = useState<RequerimentType[]>([]);
const { append, remove, fields, insert } = useFieldArray({
name: 'requirements',
control,
});
const requirementOptions = requirements?.map(
useCallback(
(requirement) => {
return {
id: requirement.id,
name: `${requirement.title} (${Math.floor(
requirement.estimate / 8
)} dias)`,
value: requirement.title,
effort: requirement.estimate,
coefficient: requirement.coefficient,
};
},
[requirements]
)
);
const handleKeyPress = (event: KeyboardEvent) => {
if (
(event.ctrlKey || event.metaKey) &&
event.key === 'ArrowUp' &&
currentIndex > 0
) {
insert(currentIndex, {});
}
if ((event.ctrlKey || event.metaKey) && event.key === 'ArrowDown') {
insert(currentIndex + 1, {});
}
if (
(event.ctrlKey || event.metaKey) &&
event.key === 'Backspace' &&
currentIndex > 0
) {
remove(currentIndex);
setFocus(`requirements.${currentIndex - 1}.title`);
}
};
useEffect(() => {
document.addEventListener('keydown', handleKeyPress);
return () => {
document.removeEventListener('keydown', handleKeyPress);
};
}, [handleKeyPress]);
useEffect(() => {
const getAllRequirements = async () => {
try {
const response = await listAllRequirements();
setRequirements(response.data.items);
} catch (err) {
console.log(err.response.data);
}
};
getAllRequirements();
append({});
}, []);
return (
<>
<div className='flex flex-col divide-y divide-zinc-700 divide-opacity-25 px-6 last:border-0 sm:px-2'>
<div className='flex flex-col'>
<div className='flex flex-row items-center justify-between gap-10'>
<Input
placeholder='Id da oportunidade vem do RD'
label='Id da oportunidade'
withoutBorder
error={errors.dealId}
{...register('dealId')}
defaultValue={dealId}
/>
<Input
placeholder='Objeto'
label='Objeto'
withoutBorder
error={errors.object}
{...register('object')}
defaultValue={object}
/>
</div>
<div className='flex flex-row items-center justify-between gap-10 pt-6'>
<Input
placeholder='Período do contrato'
label='Período do contrato'
withoutBorder
error={errors.contractPeriod}
{...register('contractPeriod')}
defaultValue={contractPeriod}
/>
<Input
placeholder='Método de pagamento'
label='Método de pagamento'
withoutBorder
error={errors.paymentMethodId}
{...register('paymentMethodId')}
defaultValue={paymentMethodId}
disabled
/>
</div>
<div className='flex items-center justify-between gap-10 pt-6'>
<Input
placeholder='Dia de vencimento da parcela'
label='Dia de vencimento da parcela'
type='number'
withoutBorder
error={errors.dueDay}
{...register('dueDay')}
defaultValue={dueDay}
/>
<div className='flex w-full flex-row items-center justify-between gap-10'>
<div className='flex w-full justify-end'>
<input
label='Total de horas'
id='totalHours'
type='number'
hidden
error={errors.totalHours}
{...register('totalHours')}
defaultValue={totalHours}
/>
</div>
<div className='flex w-full flex-col items-start gap-2'>
<input
id='totalValue'
hidden={true}
defaultValue={totalValue}
{...register('totalValue')}
/>
</div>
</div>
</div>
<hr className='mt-8 border-dark-300 pt-5' />
<div className='flex w-full justify-between'>
<h1 className='font-bold text-primary-600'>Requisitos</h1>
<Tooltip />
</div>
{fields.map((field, index) => (
<Requirement
fieldId={field.id}
errors={errors}
index={index}
register={register}
setCurrentIndex={setCurrentIndex}
requirementOptions={requirementOptions}
setValue={setValue}
currentIndex={currentIndex}
hourValue={secondPageData.hourValue}
/>
))}
<div className='flex w-full justify-end'>
<div className='flex-col'>
<div className='flex justify-end'>
<h6 className='py-2 text-white'>{`200 / horas`}</h6>
</div>
<div className='flex justify-end'>
<Title size={'bold'}>{`R$ teste`}</Title>
</div>
<div className='flex justify-end'>
<h6 className='py-2 text-white'>
<b>4 sprint</b> / ORÇADO
</h6>
</div>
<div className='flex justify-end'>
<h6 className='py-2 text-white'>
<b>{`test dias úteis`}</b> / CONTRATO
</h6>
</div>
</div>
</div>
</div>
</div>
</>
);
};
export default ThirdPage;
My requirement component - child component:
const Requirement = ({
hourValue,
fieldId,
errors,
index,
register,
setCurrentIndex,
requirementOptions,
setValue,
currentIndex,
}: SelectProps) => {
const [coefficient, setCoefficient] = useState<number>();
const [effort, setEffort] = useState<number>();
const requirementValueCalc = (effort: number, factor: number, hourValue: number) => {
const result = effort * factor * hourValue;
return result;
};
return (
<>
<div key={fieldId} className='flex flex-col gap-3'>
<div className='flex flex-row items-center justify-start gap-10'>
<div>
<Input type={'checkbox'}></Input>
</div>
<div className='w-2/6'>
<div>
{errors.requirements?.[index].title?.message && (
<span className='text-xs text-error-900'>
{errors.requirements?.[index].title?.message}
</span>
)}
</div>
<Input
id='requirementTitle'
placeholder='Título do requisito'
withoutBorder
{...register(`requirements.${index}.title`)}
onFocus={() => setCurrentIndex(index)}
className={classNames(
errors.requirements
? 'border-error-900 px-3 py-2 placeholder-error-900 focus:border-error-900 focus:ring-error-900'
: 'border-transparent px-3 py-2 placeholder-dark-300 focus:border-primary-500 focus:ring-0',
'block w-full appearance-none rounded-md border',
'bg-dark-900 text-white caret-primary-600',
'focus:outline-none sm:text-sm'
)}
/>
</div>
<div className='flex w-1/4 gap-3'>
{requirementOptions.length > 0 && (
<>
<Select
handleSetValue={(value) =>
setValue(
`requirements.${index}.typeRequirementId`,
value.id,
setCoefficient(value.coefficient),
setEffort(value.effort),
)
}
options={requirementOptions}
/>
<div className='flex ml-8 w-full gap-3'>
<Title size={'bold'}>{`R$ ${requirementValueCalc(coefficient, effort, hourValue)}`}</Title>
</div>
</>
)}
</div>
</div>
<div className='mb-5 flex flex-col gap-2'>
<div>
{errors.requirements?.[index].description?.message && (
<span className='text-xs text-error-900'>
{errors.requirements?.[index].description?.message}
</span>
)}
</div>
<textarea
id='description'
rows={2}
placeholder='Descrição do requisito'
className={classNames(
errors.requirements
? 'border-error-900 px-3 py-2 placeholder-error-900 focus:border-error-900 focus:ring-error-900'
: 'border-transparent px-3 py-2 placeholder-dark-300 focus:border-primary-500 focus:ring-0',
'block w-full appearance-none rounded-md border',
'bg-dark-900 text-white caret-primary-600',
'focus:outline-none sm:text-sm'
)}
{...register(`requirements.${index}.description`)}
/>
</div>
<hr className={currentIndex ? 'border-dark-300 pb-5' : 'invisible'} />
</div>
</>
);
};
export { Requirement };
I tried to solve it, taking the child's values ​​and sending them to the parent with a callback, but I'm not managing to keep the dynamic elements with their indexes.

How to get child click on paremt in react js

I have a child and parent compoinents as follows,
When I click on the div I am not able to get the alert in parent component but when I keep button in child component I can able to get the aler. Not sure what I am doing, Can any one please help. Thanks.
Child Comp:
const PrimaryNavigation = ({ className, data, childToParent }: IPrimaryNavigation) => {
return (
<div className={`${className} w-full bg-black grid grid-cols-12 gap-4 py-12 pl-12`}>
<div className="relative col-span-2 md:col-span-1 w-5 h-5 md:w-6 md:h-6 cursor-pointer" onClick={() => { childToParent() }}>>
<Image src={searchSvg} layout="fill" objectFit="contain" alt="hamburgerIcon" />
</div>
<div className="relative col-span-2 md:col-span-1 md:w-6 md:h-6 w-5 h-5 cursor-pointer" >
<Image src={hamburgerSvg} layout="fill" objectFit="contain" alt="searchIcon" />
</div>
</div>
)
}
Parent Comp:
const Header = ({ data }: IHeader) => {
const childToParent = () => {
alert('hi')
}
return (
<div>
<header className="w-full md-0 md:md-6 bg-black grid grid-cols-12 gap-4">
<PrimaryNavigation className="col-span-11" data={data.primaryNavigationCollection.items} childToParent={childToParent} />
</header>
</div>
)
}
export default Header

How to properly conditionally render child component in react

I have the following components : (AddBookPanel contains the AddBookForm)
I need to have the ability to display the form on click of the 'AddBookButton', and also
have the ability to hide the form while clicking the 'x' button (img in AddBookForm component), however the component doesn't seem to load properly, what could be wrong here? What do you think is the best way to organize this?
import { AddBookButton } from './AddBookButton';
import { AddBookForm } from './AddBookForm';
import { useState } from 'react';
export const AddBookPanel = () => {
const [addBookPressed, setAddBookPressed] = useState(false);
return (
<div>
<div onClick={() => setAddBookPressed(!addBookPressed)}>
<AddBookButton />
</div>
<AddBookForm initialFormActive={addBookPressed} />
</div>
);
};
import { useState } from 'react';
interface AddBookFormProps {
initialFormActive: boolean;
}
export const AddBookForm: React.FC<AddBookFormProps> = ({
initialFormActive,
}) => {
const [isFormActive, setIsFormActive] = useState(initialFormActive);
return (
<>
{isFormActive && (
<div className="fixed box-border h-2/3 w-1/3 border-4 left-1/3 top-24 bg-white border-slate-600 shadow-xl">
<div className="flex justify-between bg-slate-400">
<div>
<p className="text-4xl my-5 mx-6">Add a new Book</p>
</div>
<div className="h-16 w-16 my-3 mx-3">
<button onClick={() => setIsFormActive(!isFormActive)}>
<img
src="https://upload.wikimedia.org/wikipedia/commons/thumb/a/a0/OOjs_UI_icon_close.svg/1200px-OOjs_UI_icon_close.svg.png"
alt="close-button"
className="object-fit"
></img>
</button>
</div>
</div>
<div className="flex-col">
<div className="flex justify-between my-10 ml-5 text-xl">
<input type="text" placeholder="book name"></input>
</div>
</div>
</div>
)}
</>
);
};
You're always rendering the AddBookForm. That means in the initial render the useState is called with false. Since you never call setIsFormActive it is now stuck as "do not render".
Just don't use the useState and use the property initialFormActive directly. And maybe rename it to isFormActive. Let the parent handle the state change.
import { AddBookButton } from './AddBookButton';
import { AddBookForm } from './AddBookForm';
import { useState } from 'react';
export const AddBookPanel = () => {
const [addBookPressed, setAddBookPressed] = useState(false);
return (
<div>
<div onClick={() => setAddBookPressed(!addBookPressed)}>
<AddBookButton />
</div>
<AddBookForm initialFormActive={addBookPressed} onClose={() => setAddBookPressed(false)} />
</div>
);
};
import { useState } from 'react';
interface AddBookFormProps {
initialFormActive: boolean;
onColse: () => void;
}
export const AddBookForm: React.FC<AddBookFormProps> = ({
initialFormActive,
onClose,
}) => {
// const [isFormActive, setIsFormActive] = useState(initialFormActive); don't use this frozen state, allow the parent to control visibility
return (
<>
{initialFormActive && (
<div className="fixed box-border h-2/3 w-1/3 border-4 left-1/3 top-24 bg-white border-slate-600 shadow-xl">
<div className="flex justify-between bg-slate-400">
<div>
<p className="text-4xl my-5 mx-6">Add a new Book</p>
</div>
<div className="h-16 w-16 my-3 mx-3">
<button onClick={() => onClose()}>
<img
src="https://upload.wikimedia.org/wikipedia/commons/thumb/a/a0/OOjs_UI_icon_close.svg/1200px-OOjs_UI_icon_close.svg.png"
alt="close-button"
className="object-fit"
></img>
</button>
</div>
</div>
<div className="flex-col">
<div className="flex justify-between my-10 ml-5 text-xl">
<input type="text" placeholder="book name"></input>
</div>
</div>
</div>
)}
</>
);
};
Problem with your code is in how you tied initialFormActive to inner state of AddBookForm component. When looking at useState inside AddBookForm it is clear that prop initialFormActive only affects your initial state, and when looking at your parent component I can clearly see that you passed false as value for initialFormActive prop, thus initializing state inside AddBookForm with false value(form will stay hidden). Then you expect when you click on button, and when prop value changes(becomes true), that your <AddBookForm /> will become visible, but it will not because you just used initial value(false) from prop and after that completely decoupled from prop value change.
Since you want to control visibility outside of component, then you should attach two props to AddBookForm, isVisible and toggleVisibiliy. And do something like this:
export const AddBookPanel = () => {
const [addBookPressed, setAddBookPressed] = useState(false);
const toggleAddBookPressed = () => setAddBookPressed(p => !p);
return (
<div>
<div onClick={() => setAddBookPressed(!addBookPressed)}>
<AddBookButton />
</div>
<AddBookForm isVisible={addBookPressed} toggleVisibility={toggleAddBookPressed } />
</div>
);
};
export const AddBookForm: React.FC<AddBookFormProps> = ({
isVisible, toggleVisibility
}) => {
return (
<>
{isVisible&& (
<div className="fixed box-border h-2/3 w-1/3 border-4 left-1/3 top-24 bg-white border-slate-600 shadow-xl">
<div className="flex justify-between bg-slate-400">
<div>
<p className="text-4xl my-5 mx-6">Add a new Book</p>
</div>
<div className="h-16 w-16 my-3 mx-3">
<button onClick={toggleVisibility}>
<img
src="https://upload.wikimedia.org/wikipedia/commons/thumb/a/a0/OOjs_UI_icon_close.svg/1200px-OOjs_UI_icon_close.svg.png"
alt="close-button"
className="object-fit"
></img>
</button>
</div>
</div>
<div className="flex-col">
<div className="flex justify-between my-10 ml-5 text-xl">
<input type="text" placeholder="book name"></input>
</div>
</div>
</div>
)}
</>
);
};

|React:useOutsideClick hook gives forwardRef warning message

From firebase I fetch data and map this data to be shown in cards, every card has edit component and CardComponent(edit component parent) which use ref provided from useHandleOpen custom hook
Error message:
Function components cannot be given refs. Attempts to access this ref will fail. Did you mean to use React.forwardRef()?
Component where ref is in use
export default function EditCard(id) {
const { ref, isOpen, setIsOpen } = useHandleOpen(false);
return (
<div>
<GoKebabVertical
ref={ref}
className="cursor-pointer "
onClick={() => setIsOpen(true)}
/>
{isOpen && (
<div
ref={ref}
className="w-20 h-15 bg-white z-30 rounded-md absolute text-center
top-0 right-0
"
>
<p className="hover:bg-blue-300 hover:text-white cursor-pointer">
Edytuj
</p>
<p
className="bg-red-400 text-white font-semibold hover:bg-red-600 cursor-pointer"
onClick={() => {}}
>
Usuń
</p>
</div>
)}
</div>
);
}
export const Edit = memo(EditCard);
Card component which use ref tho and its Edit parent
const Card = ({ data, id }) => {
const editRef = useRef(null);
const { ref, isOpen, setIsOpen } = useHandleOpen(editRef);
return (
<div
className="bg-gradient-to-r from-blue-200 to-purple-500
w-64 h-28 rounded-md relative
"
>
<div className="relative top-0 left-0">
<p className="px-2 pt-1 font-bold text-gray-800 text-lg">
{data.subject_name}
</p>
<p className="px-2 text-xs text-gray-800">Sala 101</p>
</div>
<div
className="absolute top-0 right-0 rounded-r-md
rounded-b-none
bg-white w-6 h-7
grid place-items-center
"
>
<Edit id={id} />
</div>
<div className="absolute bottom-9 left-0 mb-2.5">
<p className="px-2 text-xs text-gray-800">{data.teacher}</p>
</div>
<div className=" flex direction-row mt-7 text-center w-full justify-end align-bottom pr-2 ">
<div className="rounded-lg w-14 h-7 mx-3 bg-purple-300">
<a
href={data.link_subject}
className="text-gray-800
"
target="_blank"
rel="noreferrer"
>
Lekcja
</a>
</div>
<div className="rounded-lg w-14 h-7 bg-gray-800 ">
<a
href={data.link_online_lesson}
target="_blank"
rel="noreferrer"
className="text-white"
>
Online
</a>
</div>
</div>
<div
className=" absolute bottom-0 left-0 rounded-l-md
bg-white w-7 h-6 grid place-items-center devide-solid"
>
{isOpen ? (
<AiOutlineUp
className="cursor-pointer"
ref={ref}
onClick={() => setIsOpen(true)}
/>
) : (
<AiOutlineDown
className="cursor-pointer"
ref={ref}
onClick={() => setIsOpen(true)}
/>
)}
</div>
{isOpen && (
<div
className="bg-gradient-to-r from-blue-200 to-purple-500 w-full text-left rounded-b-md p-4 "
ref={ref}
>
<p className="font-bold text-gray-800 text-sm ">Lekcje w:</p>
<p className="text-gray-800 text-sm">PN: 8-12</p>
</div>
)}
</div>
);
};
export const CardSubject = memo(Card);
Custom hook with ref:
export default function useHandleOpen() {
const [isOpen, setIsOpen] = useState(false);
const ref = useRef(null);
const handleClickOutside = (event) => {
if (ref.current && !ref.current.contains(event.target)) {
setIsOpen(!isOpen);
}
};
useEffect(() => {
document.addEventListener("click", handleClickOutside, !isOpen);
return () => {
document.removeEventListener("click", handleClickOutside, !isOpen);
};
});
return { ref, isOpen, setIsOpen };
}
Edit: Tried change it this way, but this displays warning too.
export default function useHandleOpen(ref) {
const [isOpen, setIsOpen] = useState(false);
const handleClickOutside = (event) => {
if (ref.current && !ref.current.contains(event.target)) {
setIsOpen(!isOpen);
}
};
useEffect(() => {
document.addEventListener("click", handleClickOutside, !isOpen);
return () => {
document.removeEventListener("click", handleClickOutside, !isOpen);
};
});
return { ref, isOpen, setIsOpen };
}
And use hook like this:
const editRef = useRef(null);
const { ref, isOpen, setIsOpen } = useHandleOpen(editRef);
Ok i fixed it by removing ref from places where i use onClick method for changing the state

React toggle button after mapping through list

After getting results from api call to Google books i'd like to hide the description paragraphs and have a toggle button using the css class of hidden (tailwinds css). I'm currently just console.logging the elements on the "view description" button & I'm just not sure how to target a single element after looping through the nodeList with my toggleDesc() function
React SearchBar component
import React, { useState, useEffect } from 'react';
import { FontAwesomeIcon } from '#fortawesome/react-fontawesome';
import axios from 'axios';
import { faSearch } from '#fortawesome/free-solid-svg-icons';
import SearchResult from '../search-result/search-result.component';
const SearchBar = () => {
const [searchTerm, setSearchTerm] = useState('');
const [books, setBooks] = useState({ items: [] });
useEffect(() => {
async function fetchBooks() {
const newRes = await fetch(`${API_URL}?q=${searchTerm}`);
const json = await newRes.json();
const setVis = Object.keys(json).map(item => ({
...item, isDescVisible: 'false'
}))
setBooks(setVis);
}
fetchBooks();
}, []);
const toggleDesc = (id) => {
const newBooks = books.items.map(book => book.id === id ? {...book, isDescVisible: !book.isDescVisible} : book);
console.log(newBooks);
setBooks(newBooks);
}
const onInputChange = (e) => {
setSearchTerm(e.target.value);
};
let API_URL = `https://www.googleapis.com/books/v1/volumes`;
const fetchBooks = async () => {
// Ajax call to API via axios
const result = await axios.get(`${API_URL}?q=${searchTerm}`);
setBooks(result.data);
};
// Handle submit
const onSubmitHandler = (e) => {
// prevent browser from refreshing
e.preventDefault();
// call fetch books async function
fetchBooks();
};
// Handle enter press
const handleKeyPress = (e) => {
if (e.key === 'Enter') {
e.preventDefault();
fetchBooks();
}
}
return (
<div className="search-bar p-8">
<div className="bg-white flex items-center rounded-full shadow-xl">
<input
className="rounded-l-full w-full py-4 px-6 text-gray-700 leading-tight focus:outline-none"
id="search"
type="text"
placeholder="Try 'The Hunt For Red October by Tom Clancy' "
onChange={onInputChange}
value={searchTerm}
onKeyPress={handleKeyPress}
/>
<div className="p-4">
<button
onClick={onSubmitHandler}
className="bg-blue-800 text-white rounded-full p-2 hover:bg-blue-600 focus:outline-none w-12 h-12 flex items-center justify-center"
>
<FontAwesomeIcon icon={faSearch} />
</button>
</div>
</div>
<div className='result mt-8'>
<ul>
<SearchResult books={books} toggleDesc={toggleDesc} />
</ul>
</div>
</div>
);
};
export default SearchBar;
SearchResults Component
import React from 'react';
import { LazyLoadImage } from 'react-lazy-load-image-component';
import 'react-lazy-load-image-component/src/effects/blur.css';
import './search-result.styles.scss';
const SearchResult = ({ books, toggleDesc }) => {
return (
<div className="search-result mb-6">
{books.items !== undefined &&
books.items !== null &&
books.items.map((book, index) => {
return (
<div key={index} className="book-info mb-2">
<li className="ml-4">
<div className="flex">
<LazyLoadImage
className="book-img px-4 py-2"
effect="blur"
alt={`${book.volumeInfo.title} book`}
src={`http://books.google.com/books/content?id=${book.id}&printsec=frontcover&img=1&zoom=1&source=gbs_api`}
/>
<div className="flex-1">
<h3 className="text-2xl">{book.volumeInfo.title}</h3>
<div>
<p className="flex">
<button
onClick={() => toggleDesc(book.id)}
className="bg-blue-800 mt-2 text-gray-200 rounded hover:bg-blue-400 px-4 py-3 text-sm focus:outline-none"
type="button"
>
View Description
</button>
</p>
{book.isDescVisible &&
<div
className="block border px-4 py-3 my-2 text-gray-700 desc-content"
>
<p>{book.volumeInfo.description}</p>
</div>
}
</div>
<h3 className="text-xl text-blue-800 mt-2 p-2">
Average time to read:{' '}
</h3>
</div>
</div>
<hr />
</li>
</div>
);
})}
</div>
);
};
export default SearchResult;
console
You will have to add a property to each item of your books to handle the description visibility and change it when you click the button, this is a basic example
useEffect(()=> {
fetch(url).then(res => {
const newRes = res.map(item=> ({ ...item, isDescVisible: 'false' })) // <— add the new property to all items set to false
setBooks(newRes);
})
})
<p className='flex'>
<button
onClick={() => toggleDesc(book.id)} // <—- pass the id or the whole book
className='bg-blue-800 mt-2 text-gray-200 rounded hover:bg-blue-400 px-4 py-3 text-sm focus:outline-none'
type='button'
>
View Description
</button>
</p>
//here show the desc according to the value of the property you added, no need for the hidden class
{book.isDescVisible && <div className='block border px-4 py-3 my-2 text-gray-700 desc-content'>
<p>{book.volumeInfo.description}</p>
</div>}
This function needs to be on the parent where you are setting the state
const toggleDesc = (id) => {
const newBooks = books.map(book => book.id === id ? {...book, isDescVisible: !book.isDescVisible} : book); <-- toggle the property
setBooks(newBooks); <—- save it in the state again
};

Categories

Resources