".map is not a function" error in react.js - javascript

I have developed a basic todo app using react-dnd. I am trying to get the details from the database and store it in the state. And by using the state I want to map the values retrieieved from the database.
I tried looking into the output using console.log statement, and it was something like this.
However when I try to use the map function like this:
{state.map((item, index) => (
<Draggable
key={item._id}
draggableId={item._id + ""}
index={index}
>
{console.log(item._id, "KEY")}
{(provided) => (
<li
className="list-group-item d-flex justify-content-between align-items-start align-items-center"
{...provided.draggableProps}
{...provided.dragHandleProps}
ref={provided.innerRef}
>
<div className="ms-2 me-auto">
<span className="ml-3 mr-2">
<input
type="checkbox"
className="form-check-input"
id={index}
value={index}
checked={item.selected}
onChange={(e) => {
const target = e.target.value;
const val = state[target].selected;
// console.log(val);
let tmp = Array.from(state);
tmp[target].selected = !val;
// console.log(tmp[target]);
setState(tmp);
// console.log(state);
}}
/>
</span>
<span className="font-weight-bold">{item.title}</span>
</div>
<span>
{/* <i className="bi bi-trash text-danger" /> */}
<button
className="btn btn-sm"
onClick={(e) => {
e.preventDefault();
handleDelete(item._id, index);
}}
>
<i className="bi bi-trash text-danger" />
</button>
</span>
</li>
)}
</Draggable>
Its showing an error as "state.map" is not a function
However I also tried using "state.stage.map()" . Afterwards its showing an error as state.stage is undefined. Is there any proper way of using this .map function?
I have attached the full code here below.
function ProjectsDashboard() {
useEffect(() => {
preload();
}, []);
const [state, setState] = useState([]);
const [todo, setTodo] = useState("");
const [loading, setLoading] = useState(false);
const preload = async () => {
setLoading(true);
try {
const res = await axios.get("/stages");
setState(res.data);
console.log(state, "STATE")
console.log(res.data,"DATA")
setLoading(false);
} catch (error) {
alert("Couldn't find any Todos! ");
setLoading(false);
}
};
console.log(state, "STATE")
const lists = () => (
<div className="row">
<div className="col-sm-12 col-md-4 offset-md-2 col-lg-4 offset-lg-2 border border-danger p-4">
<h3 className="text-center mb-4">Draggable List</h3>
<DragDropContext onDragEnd={handleDragEnd}>
<Droppable droppableId="todos">
{(provided) => (
<ul
className="list-group"
{...provided.droppableProps}
ref={provided.innerRef}
>
{state.stage.map((item, index) => (
<Draggable
key={item._id}
draggableId={item._id + ""}
index={index}
>
{console.log(item._id, "KEY")}
{(provided) => (
<li
className="list-group-item d-flex justify-content-between align-items-start align-items-center"
{...provided.draggableProps}
{...provided.dragHandleProps}
ref={provided.innerRef}
>
<div className="ms-2 me-auto">
<span className="ml-3 mr-2">
<input
type="checkbox"
className="form-check-input"
id={index}
value={index}
checked={item.selected}
onChange={(e) => {
const target = e.target.value;
const val = state[target].selected;
// console.log(val);
let tmp = Array.from(state);
tmp[target].selected = !val;
// console.log(tmp[target]);
setState(tmp);
// console.log(state);
}}
/>
</span>
<span className="font-weight-bold">{item.title}</span>
</div>
<span>
{/* <i className="bi bi-trash text-danger" /> */}
<button
className="btn btn-sm"
onClick={(e) => {
e.preventDefault();
handleDelete(item._id, index);
}}
>
<i className="bi bi-trash text-danger" />
</button>
</span>
</li>
)}
</Draggable>
))}
{provided.placeholder}
</ul>
)}
</Droppable>
</DragDropContext>
</div>
<div
className="col-sm-12 col-md-4 col-lg-4 border border-info p-4"
style={{ marginLeft: "10px" }}
>
<h3 className="text-center mb-4">NON-Draggable List</h3>
<ul className="list-group">
{state.map(
(item, index) =>
item.selected && (
<li className="list-group-item" key={index}>
{item.title}
</li>
)
)}
</ul>
</div>
</div>
);
const handleDragEnd = (result) => {
// console.log(result);
if (!result.destination) return;
const items = Array.from(state);
const [recordedItem] = items.splice(result.source.index, 1);
items.splice(result.destination.index, 0, recordedItem);
setState(items);
// console.log(state);
};
const handleDelete = async (id, index) => {
try {
await axios.delete(`/api/todo/${id}`);
// preload();
const temp = Array.from(state);
temp.splice(index, 1);
setState(temp);
} catch (error) {
if (`Error! ${error.response.data.err}`) {
alert(error.response.data.err);
} else {
alert(`Error ${error.response.status}: ${error.response.statusText}`);
}
}
};
const addNewTodoForm = () => (
<div className="row">
<div className="col-md-8 offset-md-2 mb-4 form-group">
<label htmlFor="newtodo">Add a New Todo Item</label>
<input
type="text"
className="form-control"
name="newtodo"
id="newtodo"
value={todo}
placeholder="Add New Todo"
required
onChange={handleChange}
/>
<button
className="btn btn-block btn-outline-primary mt-2"
onClick={handleSubmit}
>
Submit
</button>
</div>
</div>
);
const handleChange = (e) => {
e.preventDefault();
setTodo(e.target.value);
};
const handleSubmit = async (e) => {
e.preventDefault();
if (todo === "" || todo === null) {
alert(
"To add a New Todo item, please fill out the 'Add New Todo' field."
);
return;
}
const temp = {
title: todo,
};
try {
const res = await axios.post("/api/todo", temp);
setTodo("");
const tmp = Array.from(state);
tmp.push(res.data);
setState(tmp);
// preload();
} catch (error) {
if (error.response.data && error.response.data.err) {
alert(`Error! ${error.response.data.err}`);
} else {
console.log(error);
alert(`Error ${error.response.status}: ${error.response.statusText}`);
}
}
};
return (
<>
<div className="container">
<h1 className="text-center m-4 font-weight-bold text-uppercase">
DRAG TO DO{" "}
<span className="text-lowercase font-weight-normal">V1.0.1</span>
</h1>
{/* {addNewTodoForm()}*/}
{lists() }
</div>
</>
);
};
export default ProjectsDashboard;

Try this
{state.stage && state.stage.map(.........

This is because upon first render, state is initialized as an empty array. You could either initialize state as:
const [state, setState] = useState({ stage: [] });
Or write a conditional check before calling lists()
{state && state.stage ? lists() : null}

Related

im trying to only show the description of the button i press

when i click on the description button, all the mapped containers are showing their descriptions, but i only want the one thats pressed to show its description. so how can i make it so that the container that is pressed will show its id's description?
`import { useState } from "react";
export default function ServiciosCard({ profile }) {
const [normal, setNormal] = useState(true);
const [showDescripcion, setShowDescripcion] = useState(false);
const showDescripcionChangeHandler = () => {
setShowDescripcion(true);
setNormal(false);
};
return (
<>
<div
className=" space-y-4 mt-3 md:mt-0 h-[450px] md:h-[550px] overflow-y-auto
md:scrollbar scrollbar-track-[#d0e7d5] scrollbar-thumb-[#ef8eb2]
text-center "
>
{profile.servicios.map((servicio) => (
<>
{normal && (
<div
key={servicio._id}
className="bg-[#f7ede2] rounded-md w-[300px] h-[75px] "
>
<div>{servicio.unServicio}</div>
<div>1 Hr {servicio.costo}</div>
<div className=" space-x-4">
<button className="text-[#f77f00] hover:headerButton">
Reserva ahora
</button>
<button
onClick={showDescripcionChangeHandler(servicio._id)}
className="text-[#f77f00] hover:headerButton"
>
Descripcion
</button>
</div>
</div>
)}
{showDescripcion && (
<div
key={servicio._id}
className="bg-[#f7ede2] rounded-md w-[300px] h-[75px] "
>
{servicio.description}
</div>
)}
</>
))}
</div>
</>
);
}`
showDescription will show description for all item
you can create a new component Like below an pass srvicio to it.
import { useState } from "react";
export default function ServiciosCard({ profile }) {
return (
<>
<div
className=" space-y-4 mt-3 md:mt-0 h-[450px] md:h-[550px] overflow-y-auto
md:scrollbar scrollbar-track-[#d0e7d5] scrollbar-thumb-[#ef8eb2]
text-center "
>
{profile.servicios.map((servicio) => (
<ServicIo servicio={servicio} />
))}
</div>
</>
);
}
function ServicIo({servicio}){
const [normal, setNormal] = useState(true);
const [showDescripcion, setShowDescripcion] = useState(false);
const showDescripcionChangeHandler = () => {
setShowDescripcion(true);
setNormal(false);
};
return (<>
{normal && (
<div
key={servicio._id}
className="bg-[#f7ede2] rounded-md w-[300px] h-[75px] "
>
<div>{servicio.unServicio}</div>
<div>1 Hr {servicio.costo}</div>
<div className=" space-x-4">
<button className="text-[#f77f00] hover:headerButton">
Reserva ahora
</button>
<button
onClick={showDescripcionChangeHandler(servicio._id)}
className="text-[#f77f00] hover:headerButton"
>
Descripcion
</button>
</div>
</div>
)}
{showDescripcion && (
<div
key={servicio._id}
className="bg-[#f7ede2] rounded-md w-[300px] h-[75px] "
>
{servicio.description}
</div>
)}
</>)
}
in this code showDescription do each item that selected by user.

How to access function component's state variables in ReactJS?

I've been developing a website and I'm faced with an issue about accessing state varibles to a component. I've a address page(Addresses.jsx file) which has address modal. I'm also have a component which contains address modal's content (Address.jsx). I would like to access state inside Address.jsx file. How can I do that? If you can help me. I would be very appreciate.
Here is my code blocks;
Address.jsx file;
const Addresses = () => {
const [selectedAddress, setSelectedAddress] = useState();
const [modalType, setModalType] = useState();
const {
elementRef: addressModalRef,
show: showAddressModal,
hide: hideAddressModal,
} = useModal();
return (
<>
<div className="bg-light px-3 px-lg-4 py-4">
<h1 className="h4 mb-4">My Addresses</h1>
<div className="row g-3">
<div className="col-12 col-md-6 col-lg-4">
<AddressButton
onClick={() => {
setSelectedAddress(undefined);
setModalType("NewAddress");
showAddressModal();
}}
/>
</div>
{ADDRESSES.map((address, i) => (
<div className="col-12 col-md-6 col-lg-4" key={i}>
<AddressButton
{...address}
onClick={() => {
setSelectedAddress(address);
setModalType("EditAddress");
showAddressModal();
}}
/>
</div>
))}
</div>
</div>
<AddressModal
address={selectedAddress}
elementRef={addressModalRef}
hide={hideAddressModal}
modalType={modalType}
/>
</>)};
export default Addresses;
Address Modal file;
const AddressModal = ({ address, elementRef, hide, modalType }) => {
const onSaveAddress = () => {
console.log(address);
hide();
};
return (
<Modal elementRef={elementRef} centered size="lg" fullscreen>
<ModalBody>
<AddressForm address={address} /> // I would like to get this component's state in onSaveAddress funtion
</ModalBody>
<ModalFooter>
<button
type="button"
className="btn btn-primary flex-grow-1 px-5"
onClick={onSaveAddress}>
Kaydet
</button>
</ModalFooter>
</Modal>)};
export default AddressModal;
Instead of accessing child components state, which is not possible, do the following
Address Model
<AddressForm
address={address}
onSave={onSaveAddress}
/>
Address Form
const AddressForm = ({ onSave }) => {
const handleFormSubmit = () => {
onSave(formData);
};
return (
<form onSubmit={handleFormSubmit}>
</form>
);
}
Then in onSaveAddress, you will have access to the form data.

if i click button then show this button id in reactJs

i create a onclick function const showContent=(id)=>{} and if i click the perticular button they will show id in const showContent = (id)=>{console.log(id)} like this .....
inside thisCart.jsx i rendering CartStyle.jsx using map method so this delete button inside here.
Cart
function Cart() {
const [data, setData] = useState([])
useEffect(() => {
const data = JSON.parse(localStorage.getItem('Cart'));
data.map(async (v) => {
try {
axios.get(`/cart/${v}`)
.then((res) => {
return setData((preV) => {
return [...preV, res.data]
})
})
.catch(e => { console.log(e) })
} catch (e) {
console.log(e);
}
})
}, [])
const showContent=(id)=>{
console.log('this is id', id)
}
return (
<>
<div className=" cartStyle row g-3">
<div className="left col-md-4">
<button className="btn btn-primary">Proceed to Buy</button>
</div>
</div>
<div className="right col-md-8 flex flex-wrap justify-around">
{
data.map((v, i) => {
return <CartStyle
key={i}
id={i}
title={v.title}
price={v.DiscountPrice}
img={v.image}
delete={showContent(i)}
/>
})
}
</div>
</div>
</>
)
}
export { Profile, Cart };
CartStyle
this is a CartStyle means i'm passing data from Cart.jsx to CarStyle.jsx using props
const CartStyle= (props) => {
return (
<>
<div style={{ width: '22em', height: '10em'}} className=" p-2 row g-3 card container rounded-2xl shadow py-2 my-3">
<button id="delBtn" onClick={props.delete} className="btn btn-primary my-2">Delete</button>
</div>
</div>
</>
)
};
export default CartStyle;
<CartStyle
key={i}
id={i}
title={v.title}
price={v.DiscountPrice}
img={v.image}
delete={(i) => showContent(i)} // or delete={showContent}
/>
// CartStyle
<button id="delBtn" onClick={() => props.delete(props.id)} className="btn btn-primary my-2">Delete</button>
You pass your id on your parent compoenent.Then you get the id in your child component as props.
const CartStyle= (props) => {
return (
<>
<div style={{ width: '22em', height: '10em'}} className=" p-2 row g-3
card container rounded-2xl shadow py-2 my-3">
<button id="delBtn" onClick={() => props.delete(props.id)}
className="btn btn-primary my-2">Delete</button>
</div>
</>
)
};
export default CartStyle
You need to assign a function to delete prop instead of invoking it directly.
Replace
<CartStyle
delete={showContent(i)}
/>
with
<CartStyle
delete={() => showContent(i)}
/>

how to pass props from a component

how can i pass props from a select component to my app js
here my code:
const HandleSelect = ()=> {
const [selectedOption, setSelectedOption] = useState();
return(
<div className="App">
<Select
defaultValue={selectedOption}
onChange={setSelectedOption}
options={options}
/>
</div>
)
}
export default HandleSelect;
i've tried with
const Select = (props) => {
const {
defaultValue, onChange, options
} = props
console.log(onChange);
return (
<div>
</div>
)
}
export default Select
but in the app they return undefined when i try with console.log()
sorry for my english, i'm French.
Thanks for your help.
Destructure your props like this
const Select = ({defaultValue, onChange, options}) => {
return (
<div>
<p>{defaultValue}</p>
<p>{onChange}</p>
<p>{options}</p>
</div>
)
}
export default Select
or you could also do it this way
const Select = (props) => {
return (
<div>
<p>{props.defaultValue}</p>
<p>{props.onChange}</p>
<p>{props.options}</p>
</div>
)
}
export default Select
Here my app initial where i want to use the select, it's a lot of code, sorry for that !
import React, { useState, useEffect } from 'react';
import '../App.css';
import 'bootstrap/dist/css/bootstrap.min.css';
import { FiPlusCircle } from 'react-icons/fi';
import { InputGroup } from 'react-bootstrap';
import { FormControl } from 'react-bootstrap';
import { Button } from 'react-bootstrap';
import { useForm } from 'react-hook-form';
import ImageUpload from 'image-upload-react';
import { doc, setDoc, getDoc } from 'firebase/firestore';
import { decode as base64_decode, encode as base64_encode } from 'base-64';
import Select from './select';
// Initialize Cloud Firestore through Firebase
import { initializeApp } from 'firebase/app';
import { getFirestore } from 'firebase/firestore';
const object1 = { title: 'Entrecôte', category: 'Viande', describe: 'Ici la description' };
const firebaseApp = initializeApp({
//my config
});
const db = getFirestore();
const Initial = (props) => {
const [ data, setData ] = useState(object1);
const [ loadata, setLoadata ] = useState();
const [ imageSrc, setImageSrc ] = useState(); // form image source
const [ encoded, setEncoded ] = useState(); // Value
const [ title, setTitle ] = useState(''); // title
const [ category, setCat ] = useState(''); // category
const [ describe, setDesc ] = useState(''); // description
const { register, handleSubmit, formState: { errors } } = useForm();
const onSubmit = (data) => setData(data);
// set url data
const handleImageSelect = (e) => {
setImageSrc(URL.createObjectURL(e.target.files[0]));
};
useEffect(() => {
if (data) {
//form only
setTitle(data.title);
setCat(data.category);
setDesc(data.describe);
addTodo(title, category, describe, encoded); // great !
}
}, []);
// write values to firebase database
const addTodo = async () => {
const response = await fetch(imageSrc);
const blob = await response.blob();
var reader = new FileReader();
reader.onload = () => {
setEncoded(reader.result);
};
reader.readAsDataURL(blob);
if (encoded && data) {
await setDoc(doc(db, 'User', 'user000'), {
category: category,
title: title,
describe: describe,
image: encoded
});
}
};
function getScrollHeight(elm) {
var savedValue = elm.value;
elm.value = '';
elm._baseScrollHeight = elm.scrollHeight;
elm.value = savedValue;
}
function onExpandableTextareaInput({ target: elm }) {
// make sure the input event originated from a textarea and it's desired to be auto-expandable
if (!elm.classList.contains('autoExpand') || !elm.nodeName === 'TEXTAREA') return;
var minRows = elm.getAttribute('data-min-rows') | 0,
rows;
!elm._baseScrollHeight && getScrollHeight(elm);
elm.rows = minRows;
rows = Math.ceil((elm.scrollHeight - elm._baseScrollHeight) / 16);
elm.rows = minRows + rows;
}
// global delegated event listener
document.addEventListener('input', onExpandableTextareaInput);
// Ici je veux retourner le produit (lecture)
const getUser = async () => {
const list = [];
const docRef = doc(db, 'User', 'user000');
const docSnap = await getDoc(docRef);
if (docSnap.exists()) {
list.push(docSnap.data());
const newlist = list[0];
setLoadata(newlist);
} else {
console.log('No such document!');
}
};
useEffect(() => {
getUser();
}, []);
// console.log('propsinou', props);
return (
<div className="container-fluid css-selector m-0 p-0" style={{ height: '100vh' }}>
<div className="row m-0 p-0">
<div className="col-12 row m-0">
{/* column card */}
<div className="col-md-1 cardColor mt-5 text-center text-white size">
<h4 className="mt-3 mb-4"> Bienvenue </h4>
<div className="round">
<FiPlusCircle size={40} />
</div>
<p>Ajouter menu</p>
</div>
<div className="col-11 row space m-0 justify-content-center">
<h1 className="m-0 text-white text-center mt-5">Bienvenue sur votre Dashboard</h1>
<div className="col-10 row m-0">
<h4 className="m-0 text-white p-3">Étape 1 : ajouter du contenu </h4>
{/* First card */}
<div className="col-3 text-center card">
{loadata ? (
<div class="container">
<h3 className="m-0 text-success p-3">Titre</h3>
<InputGroup className="mb-3">
<InputGroup.Text id="basic-addon1">📌</InputGroup.Text>
<FormControl
placeholder={loadata.title}
aria-label="Titre du menu"
aria-describedby="basic-addon1"
{...register('title')} // onChange={e=>
// this.setState({ val: e.target.value })}
/>
</InputGroup>
<h3 className="m-0 text-success">Catégorie</h3>
<InputGroup className="mb-3 mt-3">
<InputGroup.Text id="basic-addon1">📜</InputGroup.Text>
<FormControl
placeholder={loadata.category}
aria-label="Username"
aria-describedby="basic-addon1"
{...register('category')} // onChange={e=>
// this.setState({ val: e.target.value })}
/>
</InputGroup>
</div>
) : (
<div class="container">
<h3 className="m-0 text-success p-3">Titre</h3>
<InputGroup className="mb-3">
<InputGroup.Text id="basic-addon1">📌</InputGroup.Text>
<FormControl
placeholder="titrent"
aria-label="Titre du menu"
aria-describedby="basic-addon1"
{...register('title')} // onChange={e=>
// this.setState({ val: e.target.value })}
/>
</InputGroup>
<h3 className="m-0 text-success">Catégorie</h3>
<InputGroup className="mb-3 mt-3">
<InputGroup.Text id="basic-addon1">📜</InputGroup.Text>
<FormControl
placeholder="Username"
aria-label="Username"
aria-describedby="basic-addon1"
{...register('category')} // onChange={e=>
// this.setState({ val: e.target.value })}
/>
</InputGroup>
</div>
)}
</div>
<div className="col-3 card offset-1">
<div className="container">
<h3 className="m-0 text-success p-3 text-center">Description</h3>
{loadata ? (
<textarea
className="autoExpand"
rows="3"
data-min-rows="3"
placeholder={loadata.describe}
{...register('describe')}
autoFocus
/>
) : (
<textarea
className="autoExpand"
rows="3"
data-min-rows="3"
placeholder={'Entrez la description'}
{...register('describe')}
autoFocus
/>
)}
</div>
</div>
<div className="col-3 offset-1 p-absolute">
<ImageUpload
className="border-r"
handleImageSelect={handleImageSelect}
imageSrc={imageSrc}
setImageSrc={setImageSrc}
style={{
width: '100%',
height: '100%',
background: 'gold'
}}
/>
</div>
</div>
<div className="col-10 row m-0">
<div className="col-3"></div>
<h4 className="m-0 text-white p-3 mt-5">Étape 2 : Choisir la catégorie & valider </h4>
{/* First card */}
<div className="col-3 text-center card">
<div class="container">
<h3 className="m-0 text-success p-3">Catégorie</h3>
<Select />
</div>
</div>
<div className="col-3 offset-1 text-center card">
<div class="container">
<h3 className="m-0 text-success p-3">Valider</h3>
{/* <Button /> */}
<Button variant="success" onClick={handleSubmit(onSubmit)}>
Envoyer les données
</Button>{' '}
</div>
</div>
</div>
</div>
{/* Boutton Select*/}
</div>
</div>
</div>
);
};
export default Initial;

Next js - Setting DOM element scrollHeight in parent component from child component

I have created an accordion within an accordion
/pages/profile.js passes all the data the first component /components/loved_one.js which renders the first DOM container. When the container button is clicked, the toggleAccordion function sets the scrollheight of the ref content (the container of the accordion within). Which works great as none of the elements within are expanded, and so the height is calculated.
The accordion within /components/event.js does the same thing. However this now expands and the parent accordion container above is now too small.
If I collapse and expand the parent accordion, it works, as the inner elements are expanded and so can set the correct height again.
So I'm trying to find a way, when I set the height of the inner accordion container, I also trigger the parent accordion container to re-address it's height.
Anyone know how I could do this? Appreciate any help.
Here's the code: -
/pages/profile.js
export const Profile = ({ loved_ones, events, messages, mementos }) => {
const [session, loading] = useSession();
if (loading) return <div>loading...</div>;
if (!session) return <div>no session</div>;
return (
<Layout>
{session && (
<>
<h1>{session.user.name}</h1>
</>
)}
{loved_ones.map((loved_one, index) => (
<LovedOne
key={index}
id={loved_one.id}
firstname={loved_one.firstname}
surname={loved_one.surname}
email={loved_one.email}
events={events}
messages={messages}
mementos={mementos}
/>
))}
<style jsx>{`
.avatar {
width: 220px;
border-radius: 10px;
}
`}</style>
</Layout>
);
};
export async function getServerSideProps(req, res) {
const session = await getSession(req);
const prisma = new PrismaClient({
log: ["query", "info", "warn"],
});
if (!session) {
return {
props: {},
redirect: {
destination: "/login",
permanent: false,
},
};
}
const loved_one = await prisma.loved_one.findMany({
where: {
user_id: session.user.user_id,
},
});
const events = await prisma.events.findMany({
where: {
user_id: session.user.user_id,
},
});
const messages = await prisma.messages.findMany({
where: {
user_id: session.user.user_id,
},
});
const mementos = await prisma.mementos.findMany({
where: {
user_id: session.user.user_id,
},
include: {
package_size: true,
},
});
const stringifiedData = JSON.stringify(loved_one);
const loved_ones_data = JSON.parse(stringifiedData);
const stringifiedDataEvents = safeJsonStringify(events);
const events_data = JSON.parse(stringifiedDataEvents);
const stringifiedDataMessages = safeJsonStringify(messages);
const messages_data = JSON.parse(stringifiedDataMessages);
const stringifiedDataMementos = safeJsonStringify(mementos);
const mementos_data = JSON.parse(stringifiedDataMementos);
return {
props: {
loved_ones: loved_ones_data,
events: events_data,
messages: messages_data,
mementos: mementos_data,
},
};
}
export default Profile;
/components/loved_one.js
export const LovedOne = (props) => {
const [setActive, setActiveState] = useState("");
const [setHeight, setHeightState] = useState("0px");
const [setIcon, setIconState] = useState("fas fa-plus");
const content = useRef();
function toggleAccordion() {
setActiveState(setActive === "" ? "active" : "");
setHeightState(
setActive === "active" ? "0px" : `${content.current.scrollHeight}px`
);
setIconState(setActive === "active" ? "fas fa-plus" : "fas fa-minus");
}
return (
<>
<div className="item-container teal lighten-5">
<div className="row item teal darken-1">
<div className="col m1">
<button className={`expand ${setActive}`} onClick={toggleAccordion}>
<i className={`${setIcon} white-text small`}></i>
</button>
</div>
<div className="col m4 item-title">
<span className="teal-text text-darken-4">Loved One: </span>
{props.firstname} {props.surname}
</div>
<div className="col m5 item-title">
<span className="teal-text text-darken-4">Email: </span>
{props.email}
</div>
<div className="col m1 offset-m1">
<button className="btn-floating btn-small waves-effect waves-light">
<i className="fas fa-trash-alt white-text small"></i>
</button>
</div>
</div>
<div
className="item-content"
ref={content}
style={{ maxHeight: `${setHeight}` }}
>
{props.events.map((loved_one_event, index) => {
if (props.id === loved_one_event.loved_one_id)
return (
<Event
key={index}
id={loved_one_event.id}
loved_one_id={loved_one_event.loved_one_id}
date={loved_one_event.date}
anniversary={loved_one_event.anniversary}
messages={[props.messages]}
mementos={props.mementos}
/>
);
})}
</div>
</div>
</>
);
};
export default LovedOne;
/components/events.js
export const Event = (props) => {
const [setActive, setActiveState] = useState("");
const [setHeight, setHeightState] = useState("0px");
const [setIcon, setIconState] = useState("fas fa-plus");
const content = useRef();
const [startDate, setStartDate] = useState(new Date());
function toggleAccordion() {
setActiveState(setActive === "" ? "active" : "");
setHeightState(
setActive === "active" ? "0px" : `${content.current.scrollHeight}px`
);
setIconState(setActive === "active" ? "fas fa-plus" : "fas fa-minus");
}
return (
<>
<div className="item-container teal lighten-4">
<div className="row event teal lighten-1">
<div className="col m1">
<button className={`expand ${setActive}`} onClick={toggleAccordion}>
<i className={`${setIcon} white-text small`}></i>
</button>
</div>
<div className="col m4 item-title">
<span className="teal-text text-darken-4">Event Date: </span>
</div>
<div className="col m3 item-title">
<span className="teal-text text-darken-4">Anniversary: </span>
{props.anniversary}
</div>
<div className="col m1 offset-m2">
<button className="btn-floating btn-small waves-effect waves-light">
<i className="fas fa-trash-alt white-text small"></i>
</button>
</div>
</div>
<div
className="event-content"
ref={content}
style={{ maxHeight: `${setHeight}` }}
>
{props.messages[0].map((message, index) => {
if (props.id === message.event_id)
return (
<Message
key={index}
id={message.id}
event_id={message.event_id}
content={message.content}
/>
);
})}
</div>
<div
className="event-content"
ref={content}
style={{ maxHeight: `${setHeight}` }}
>
{props.mementos.map((memento, index) => {
if (props.id === memento.event_id)
return (
<Memento
key={index}
id={memento.id}
event_id={memento.event_id}
package_size={memento.package_size}
/>
);
})}
</div>
</div>
</>
);
};
export default Event;
Found what to do. I needed to set the height to auto, rather than the maxHeight
.item-content {
overflow: hidden;
height: 0px;
transition: max-height 0.2s ease-out;
}
function toggleAccordion() {
setActiveState(setActive === "" ? "active" : "");
setHeightState(setActive === "active" ? "0px" : `auto`);
setIconState(setActive === "active" ? "fas fa-plus" : "fas fa-minus");
}
return (
<>
<div className="item-container teal lighten-5">
<div className="row item teal darken-1">
<div className="col m1">
<button className={`expand ${setActive}`} onClick={toggleAccordion}>
<i className={`${setIcon} white-text small`}></i>
</button>
</div>
<div className="col m4 item-title">
<span className="teal-text text-darken-4">Loved One: </span>
{props.firstname} {props.surname}
</div>
<div className="col m5 item-title">
<span className="teal-text text-darken-4">Email: </span>
{props.email}
</div>
<div className="col m1 offset-m1">
<button className="btn-floating btn-small waves-effect waves-light">
<i className="fas fa-trash-alt white-text small"></i>
</button>
</div>
</div>
<div
className="item-content"
ref={content}
style={{ height: `${setHeight}` }}
>

Categories