Error: Uncaught [Error: Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: undefined.
Learning react from https://www.udemy.com/course/react-the-complete-guide-incl-redux
Section 8: Working with refs & portals
Instructions:
Exposing Component APIs
Your working on a part of an application that contains a form which should be resettable from outside that form.
A colleague prepared a Form
component that contains a couple of dummy inputs and a "Save" button that’s not doing anything.
Your task is to expose a clear()
function from inside that Form
component so that other components that use the Form
component can call that function to reset the form.
Because that exposed clear()
function should call the form’s built-in reset()
method (the JS form object, which is the underlying object of the <form>
element, has a reset()
method that does exactly what its name implies).
So the Form
component should be usable like this:
function SomeComponent() { const form = React.useRef(); function handleClear() { form.current.clear(); } return <Form ref={form}/>}
After adding this feature to the Form
component you should tweak the App
component to establish a "connection" to the Form
component and call the newly exposed clear()
method from inside the App
component’s handleRestart()
function.
So you should add code similar to the above code snippet to the App
component.
Important: In this Udemy exercise workspace, any React Hooks (and other React functions!) must be accessed directly on the imported React
object (import React from 'react'
) – for example: React.useState()
.
-- App.js
import React from 'react';
import Form from './Form';
// Don't change the name of the 'App'
// function and keep it a named export
export default function App() {
const formRef = React.useRef();
function handleRestart() {
formRef.current.clear();
}
return (
<div id="app">
<button onClick={handleRestart}>Restart</button>
<Form ref={formRef} />
</div>
);
}
-- Form.js
import React from 'react';
const FormComponent = React.forwardRef((props, ref) => {
const formRef = React.useRef();
React.useImperativeHandle(ref, () => ({
clear() {
formRef.current.reset();
}
}), []);
return (
<form ref={formRef}>
<p>
<label>Name</label>
<input type="text" />
</p>
<p>
<label>Email</label>
<input type="email" />
</p>
<p id="actions">
<button type="button">Save</button> {/* Added type="button" to prevent form submission */}
</p>
</form>
);
});
export default FormComponent;
-- index.css
@import url('https://fonts.googleapis.com/css2?family=Raleway:wght@400;700&family=Lato:wght@400;700&display=swap');
* {
box-sizing: border-box;
}
body {
margin: 0;
font-family: 'Raleway', sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
background: linear-gradient(#180d27, #0c0219);
color: #e5d9f1;
min-height: 100vh;
}
#app {
margin: 2rem auto;
padding: 1rem;
max-width: 30rem;
text-align: center;
border-radius: 6px;
background: linear-gradient(#341a89, #3a1967);
box-shadow: 0 0 8px rgba(0, 0, 0, 0.3);
}
button {
font-family: 'Lato', sans-serif;
font-size: 1rem;
font-weight: 700;
padding: 0.5rem 1rem;
border: 1px solid white;
border-radius: 6px;
background: none;
color: #e5d9f1;
cursor: pointer;
transition: all 0.2s ease-in-out;
}
form button {
background: linear-gradient(#9e21c8, #8b179c);
border: none;
}
form {
width: 90%;
max-width: 40rem;
margin: 3rem auto;
}
form label {
display: block;
margin-bottom: 0.5rem;
font-size: 0.8rem;
text-align: left;
text-transform: uppercase;
font-weight: bold;
letter-spacing: 0.1rem;
}
form input {
width: 100%;
padding: 0.5rem;
border: 1px solid #e5d9f1;
border-radius: 6px;
background: none;
color: #e5d9f1;
font-size: 1rem;
font-family: 'Lato', sans-serif;
margin-bottom: 1rem;
}
#actions {
text-align: right;
}
It’s working when I try from local setup but fails udemy test cases with below errors –
Warning: React.jsx: type is invalid -- expected a string (for built-in components) or a class/function (for composite components) but got: undefined. You likely forgot to export your component from the file it's defined in, or you might have mixed up default and named imports.
Error: Uncaught [Error: Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: undefined. You likely forgot to export your component from the file it's defined in, or you might have mixed up default and named imports.]
at reportException (/eval/node_modules/jsdom/lib/jsdom/living/helpers/runtime-script-errors.js:66:24)
at innerInvokeEventListeners (/eval/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:353:9)
at invokeEventListeners (/eval/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:286:3)
at HTMLUnknownElementImpl._dispatch (/eval/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:233:9)
at HTMLUnknownElementImpl.dispatchEvent (/eval/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:104:17)
at HTMLUnknownElement.dispatchEvent (/eval/node_modules/jsdom/lib/jsdom/living/generated/EventTarget.js:241:34)
at Object.invokeGuardedCallbackDev (/eval/node_modules/react-dom/cjs/react-dom.development.js:4213:16)
at invokeGuardedCallback (/eval/node_modules/react-dom/cjs/react-dom.development.js:4277:31)
at beginWork$1 (/eval/node_modules/react-dom/cjs/react-dom.development.js:27451:7)
at performUnitOfWork (/eval/node_modules/react-dom/cjs/react-dom.development.js:26560:12)
at workLoopSync (/eval/node_modules/react-dom/cjs/react-dom.development.js:26466:5)
at renderRootSync (/eval/node_modules/react-dom/cjs/react-dom.development.js:26434:7)
at performConcurrentWorkOnRoot (/eval/node_modules/react-dom/cjs/react-dom.development.js:25738:74)
at flushActQueue (/eval/node_modules/react/cjs/react.development.js:2667:24)
at act (/eval/node_modules/react/cjs/react.development.js:2582:11)
at /eval/node_modules/@testing-library/react/dist/act-compat.js:63:25
at renderRoot (/eval/node_modules/@testing-library/react/dist/pure.js:159:26)
at render (/eval/node_modules/@testing-library/react/dist/pure.js:246:10)
at Object.<anonymous> (/eval/test/App.spec.js:30:11)
at Promise.then.completed (/eval/node_modules/jest-circus/build/utils.js:298:28)
at new Promise (<anonymous>)
at callAsyncCircusFn (/eval/node_modules/jest-circus/build/utils.js:231:10)
at _callCircusTest (/eval/node_modules/jest-circus/build/run.js:316:40)
at processTicksAndRejections (node:internal/process/task_queues:95:5)
at _runTest (/eval/node_modules/jest-circus/build/run.js:252:3)
at _runTestsForDescribeBlock (/eval/node_modules/jest-circus/build/run.js:126:9)
at _runTestsForDescribeBlock (/eval/node_modules/jest-circus/build/run.js:121:9)
at run (/eval/node_modules/jest-circus/build/run.js:71:3)
at runAndTransformResultsToJestFormat (/eval/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapterInit.js:122:21)
at jestAdapter (/eval/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:79:19)
at runTestInternal (/eval/node_modules/jest-runner/build/runTest.js:367:16)
at runTest (/eval/node_modules/jest-runner/build/runTest.js:444:34) {
detail: Error: Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: undefined. You likely forgot to export your component from the file it's defined in, or you might have mixed up default and named imports.
at createFiberFromTypeAndProps (/eval/node_modules/react-dom/cjs/react-dom.development.js:28439:17)
at createFiberFromElement (/eval/node_modules/react-dom/cjs/react-dom.development.js:28465:15)
at reconcileSingleElement (/eval/node_modules/react-dom/cjs/react-dom.development.js:15750:23)
at reconcileChildFibers (/eval/node_modules/react-dom/cjs/react-dom.development.js:15808:35)
at reconcileChildren (/eval/node_modules/react-dom/cjs/react-dom.development.js:19174:28)
at updateHostRoot (/eval/node_modules/react-dom/cjs/react-dom.development.js:19883:5)
at beginWork (/eval/node_modules/react-dom/cjs/react-dom.development.js:21615:14)
at HTMLUnknownElement.callCallback (/eval/node_modules/react-dom/cjs/react-dom.development.js:4164:14)
at HTMLUnknownElement.callTheUserObjectsOperation (/eval/node_modules/jsdom/lib/jsdom/living/generated/EventListener.js:26:30)
at innerInvokeEventListeners (/eval/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:350:25)
at invokeEventListeners (/eval/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:286:3)
at HTMLUnknownElementImpl._dispatch (/eval/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:233:9)
at HTMLUnknownElementImpl.dispatchEvent (/eval/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:104:17)
at HTMLUnknownElement.dispatchEvent (/eval/node_modules/jsdom/lib/jsdom/living/generated/EventTarget.js:241:34)
at Object.invokeGuardedCallbackDev (/eval/node_modules/react-dom/cjs/react-dom.development.js:4213:16)
at invokeGuardedCallback (/eval/node_modules/react-dom/cjs/react-dom.development.js:4277:31)
at beginWork$1 (/eval/node_modules/react-dom/cjs/react-dom.development.js:27451:7)
at performUnitOfWork (/eval/node_modules/react-dom/cjs/react-dom.development.js:26560:12)
at workLoopSync (/eval/node_modules/react-dom/cjs/react-dom.development.js:26466:5)
at renderRootSync (/eval/node_modules/react-dom/cjs/react-dom.development.js:26434:7)
at performConcurrentWorkOnRoot (/eval/node_modules/react-dom/cjs/react-dom.development.js:25738:74)
at flushActQueue (/eval/node_modules/react/cjs/react.development.js:2667:24)
at act (/eval/node_modules/react/cjs/react.development.js:2582:11)
at /eval/node_modules/@testing-library/react/dist/act-compat.js:63:25
at renderRoot (/eval/node_modules/@testing-library/react/dist/pure.js:159:26)
at render (/eval/node_modules/@testing-library/react/dist/pure.js:246:10)
at Object.<anonymous> (/eval/test/App.spec.js:30:11)
at Promise.then.completed (/eval/node_modules/jest-circus/build/utils.js:298:28)
at new Promise (<anonymous>)
at callAsyncCircusFn (/eval/node_modules/jest-circus/build/utils.js:231:10)
at _callCircusTest (/eval/node_modules/jest-circus/build/run.js:316:40)
at processTicksAndRejections (node:internal/process/task_queues:95:5)
at _runTest (/eval/node_modules/jest-circus/build/run.js:252:3)
at _runTestsForDescribeBlock (/eval/node_modules/jest-circus/build/run.js:126:9)
at _runTestsForDescribeBlock (/eval/node_modules/jest-circus/build/run.js:121:9)
at run (/eval/node_modules/jest-circus/build/run.js:71:3)
at runAndTransformResultsToJestFormat (/eval/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapterInit.js:122:21)
at jestAdapter (/eval/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:79:19)
at runTestInternal (/eval/node_modules/jest-runner/build/runTest.js:367:16)
at runTest (/eval/node_modules/jest-runner/build/runTest.js:444:34),
type: 'unhandled exception'
}
Coding Exercise
2
Answers
I invested a lot of time in this exercise comparing the given answer with my code. At the end, I found that removing the default property in the export of App() fixed the issue (i.e. simply do export function App(){...}instead of export default function App(){...}).
At the beginning, you imported
forwardRef
from react. to use it in you component. then you exporting a function calledforwardRef
that returning a jsx form. the issue is you should’t name component the same as the function you’re wrapping withforwardRef
. so change your component something like this :YourComponentName
Change this to your component name that cannot be the nameforwardRef
Thanks!