Reputation: 11
I would like to create a new instance of a component and then use a function within that component to add add a new object. Nothing works for me. Here is my code:
The component that holds the list and the function to add new eventCard
function EventDay (props) {
const [ events, setEvents ] = useState([{eventName: "first event"}]);
function addEvent(eventCard) {
setEvents( prevEvents => [...prevEvents, eventCard]);
}
return console.log(events);
}
export default EventDay;
the component that wants to access the addEvent function
import EventDay from "./EventDay"
function App() {
const eventDay = new EventDay();
eventDay.addEvent({eventName: "New Event"});
}
I get an error addEvent is not a function. I tried to export it but I can't since it's a function within a function. How can I achieve the above?
Upvotes: 1
Views: 95
Reputation: 191976
Hooks can only be use inside functional components, and they cannot be used as constructors. The standard answer would be to move the state handling to the wrapping component (App), and pass the state to EventDay:
const { useState, useCallback, useEffect } = React;
const EventDay = ({ events }) => events.map((o, i) => (<li key={i}>{o.eventName}</li>));
function App() {
const [events, setEvents] = useState([{eventName: "first event"}]);
const addEvent = useCallback(eventCard => setEvents(prevEvents => [...prevEvents, eventCard]), []);
useEffect(() => {
setTimeout(() => {
addEvent({eventName: "new event"});
}, 1000);
}, [addEvent])
return (
<ul>
<EventDay events={events} />
</ul>
);
}
ReactDOM.render(
<App />,
root
)
<script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
<div id="root"></div>
However, if you must get a function from the component, you can use ref
with a the useImperativeHandle
hook:
const { forwardRef, useState, useImperativeHandle, useRef, useEffect } = React;
const EventDay = forwardRef((props, ref) => {
const [events, setEvents] = useState([{eventName: "first event"}]);
useImperativeHandle(ref, () => ({
addEvent(eventCard) {
setEvents(prevEvents => [...prevEvents, eventCard]);
}
}));
return events.map((o, i) => (<li key={i}>{o.eventName}</li>));
});
function App() {
const eventRef = useRef();
useEffect(() => {
setTimeout(() => {
eventRef.current.addEvent({eventName: "new event"});
}, 1000);
}, [])
return (
<ul>
<EventDay ref={eventRef} />
</ul>
);
}
ReactDOM.render(
<App />,
root
)
<script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
<div id="root"></div>
Upvotes: 1