X is not a function in React JS - javascript

In my App.js component I have this state :
const [searchText, setSearchText] = useState('');
I have passed this into the Search component as a prop to update the text that I write in the search bar that I have created in the search component.
This is the error that is coming : bundle.js:461 Uncaught TypeError: props.handleSearchNote is not a function
Here is how i have passed in the function in App.js:
And this is my search component:
import React from 'react'
import { MdSearch } from 'react-icons/md'
const Search = (props) => {
return (
<div className='search'>
<MdSearch className='search-icons' size='1.3em' />
<input
onChange={(event) =>
props.handleSearchNote(event.target.value)
}
type='text'
placeholder='type to search...'
/>
</div>
);
};
export default Search;
This is where I have passed the Search component in App.js
return (
<>
<div className='container'>
<Search handlSearchNote={setSearchText} />
{console.log(searchText)}
<NotesList
notes={notes.filter((note) => note.text.toLowerCase().includes(searchText))}
handleAddNote={addNote}
handleDeleteNote={deleted} />
</div>
</>
);
}
export default App;

You're assigning setSearchText to handlSearchNote not handleSearchNote. You forgot the 'e' in handle. This happens to me all the time😅.

Related

Cannot read properties of undefined (reading *)

Hey I am learning reactjs as much as i have learned I am trying to make note app
my code given below
my App.js file
import React , {useEffect, useState} from "react"
import { nanoid } from "nanoid"
import Editor from './Note/Editor'
import Sidebar from "./Note/Sidebar"
function App() {
const [notes , setNotes] = useState(JSON.parse(localStorage.getItem("notes"))||[])
const [currentNoteID , setCurrentNoteID] = useState(false)
useEffect(()=>{
localStorage.setItem("notes" , JSON.stringify(notes))
},[notes])
function createNewNotes(){
const newNotes = {
id: nanoid(),
title:"untitled",
body: "sdasda",
lastModified: Date.now()
}
setNotes(prevNote => [newNotes , ...prevNote])
setCurrentNoteID(newNotes.id)
}
function deleteNote(noteID){
setNotes(prevNote => prevNote.filter(note=> note.id !== noteID ))
}
function getNotes(){
return notes.find((note)=> note.id === currentNoteID)
}
return (
<div className="note">
<Sidebar
notes={notes}
createNewNotes={createNewNotes}
currentNoteID={currentNoteID}
setCurrentNoteID={setCurrentNoteID}
deleteNote={deleteNote}
/>
<Editor
notes={getNotes()}
currentNoteID={currentNoteID}/>
</div>
);
}
export default App;
my Sidebar.js file
import React from 'react'
import './style.css'
export default function Sidebar(props){
return(
<>
<div className='sidebar' >
<div className='sidebar-header'>
<h3>Notes</h3>
<button className='add' onClick={props.createNewNotes} >Add</button>
</div>
{ props.notes.map((note)=>{
return(
<div key={note.id}
className={`${note.id===props.currentNoteID ? "active" : ""}`}
onClick={()=>props.setCurrentNoteID(note.id)}
>
<div>
<div className="sidebar-tab">
<div className='sidebar-title'>
<p className='title'>Untitled</p>
<button className='delete' onClick={()=>props.deleteNote(note.id)}>Delete</button>
</div>
<p className='note-preview'>summary of text</p>
</div>
</div>
</div>
)
})}
</div>
</>
)
}
my Editor.js file
import React , {useState} from "react";
import './style.css'
export default function Editor(props){
const [edit , setEdit] = useState(props.notes)
function handleChange(event){
const {name , value} = event.target
setEdit(prevNote=> {
return {
...prevNote,
[name] : value
}
})
}
if(!props.currentNoteID)
return <div className="no-note">no note active</div>
return(
<>
<div className="main">
<input type="text" className="main-input" name="title" placeholder="Enter title here" value={edit.title} onChange={handleChange} autoFocus/>
<textarea className="main-textarea" name="body" placeholder="Type your notes" value={edit.body} onChange={handleChange} />
<div className="preview">
<h1 className="preview-title">{edit.title}</h1>
<div className="main-preview">{edit.body}</div>
</div>
</div>
</>
)
}
whenever i click add button or any sidebar button it shows me error
Uncaught TypeError: Cannot read properties of undefined (reading 'title')
please help me out how to fix this issue
You're expecting getNotes (which should probably be named getActiveNote, IMHO) to re-run every time notes or currentNoteID change.
To achieve this, you have to declare it as a callback (useCallback) and to declare its dependencies. Also you want to place the result in state (e.g: activeNote):
const getActiveNote = useCallback(
() => notes.find((note) => note.id === currentNoteID),
[notes, currentNoteID]
);
const [activeNote, setActiveNote] = useState(getActiveNote());
useEffect(() => {
setActiveNote(getActiveNote());
}, [getActiveNote]);
// ...
<Editor note={activeNote} />
... at which point, you no longer need the currentNoteID in the <Editor /> as you can get it from props.note.id.
See it working here: https://codesandbox.io/s/crazy-glade-qb94qe?file=/src/App.js:1389-1448
Note: the same thing needs to happen in <Editor>, when note changes:
useEffect(() => setEdit(note), [note]);

Why React doesn't display content from components? [duplicate]

This question already has answers here:
Curly Brackets in Arrow Functions
(3 answers)
Closed 1 year ago.
I am new at React and I am trying to do a very simple Todo app but I already got stuck.
I initialized with create-react-app and somehow nothing is showing when I loop through the state and call a component passing data to it.
Here is the App.js:
import React, { useState } from 'react';
import Todo from './components/Todo';
function App() {
const [title, setTitle] = useState(['test1', 'test2', 'test3'])
return (
<div className="App">
{title.map(item => {
<div>
<Todo item={item} />
</div>
})}
</div>
);
}
export default App;
And this is the Todo.js:
import React from 'react';
const Todo = ({item}) => {
return <div>{item}</div>
}
export default Todo;
The Todo component is called from the right folder (I checked many times), the files are saved and React is not returning any error, it just displays nothing in the DOM. If I loop through the title and display its content from the app.js it displays everything as normal.
Also, a console.log from inside Todo component is not triggered meaning, somehow the component is not imported.
What am I doing wrong here?
It's not displaying because you are not returning anything from map
Try something like below:-
Return from map using return keyword
{title.map(item => {
return (
<div>
<div>{item}</div>
</div>
)
})}
OR implicitly return line below:-
{title.map(item => (
<div>
<div>{item}</div>
</div>
))}
try something like this:
import React, { useState } from 'react';
import Todo from './components/Todo';
function App() {
const [title, setTitle] = useState(['test1', 'test2', 'test3'])
return (
<div className="App">
{title.map(item => {
return(
<div>
<Todo item={item} />
</div>
);
})}
</div>
);
}
export default App;
or
import React, { useState } from 'react';
import Todo from './components/Todo';
function App() {
const [title, setTitle] = useState(['test1', 'test2', 'test3'])
return (
<div className="App">
{title.map(item =>(
<div>
<Todo item={item} />
</div>
))}
</div>
);
}
export default App;

ref.current is null in gatsby react app when trying to execute recaptcha

I am trying to use this https://react-hook-form.com/get-started npm package with this package https://www.npmjs.com/package/react-google-recaptcha in gatsby and react. I want to use the invisible recaptcha it looks like I have to execute the recaptcha which I am trying to do by creating a react ref but it says the rec.current is null, Not quote sure what to do. The onSubmit function is where I am getting the null result, I was assuming I would be able to fire the captcha here and then get back the captcha value to later send off to google in my lambda function for verification.
Thanks ahead of time
Here is my code thus far
import React, { useState } from "react"
import Layout from "../components/layout"
import Img from "gatsby-image"
import { graphql, Link } from "gatsby"
import { CartItems } from "../components/cart"
import { useForm } from "react-hook-form"
import ReCAPTCHA from "react-google-recaptcha"
const StoreDetails = ({ data }) => {
const { register, handleSubmit, watch, errors } = useForm()
const recaptchaRef = React.createRef()
const onSubmit = data => {
console.log(recaptchaRef)
recaptchaRef.current.execute() //this shows up null
}
function onChange(value) {
console.log("Captcha value:", value)
}
function error(value) {
alert(value)
}
return (
<>
{data.allSanityProducts.edges.map(({ node: product }, i) => {
return (
<React.Fragment key={i}>
<Item>
<Img
fluid={product.featureImage && product.featureImage.asset.fluid}
/>
<div>
...
<form onSubmit={handleSubmit(onSubmit)}>
{/* register your input into the hook by invoking the "register" function */}
<input name="example" defaultValue="test" ref={register} />
{/* include validation with required or other standard HTML validation rules */}
<input
name="exampleRequired"
ref={register({ required: true })}
/>
{/* errors will return when field validation fails */}
{errors.exampleRequired && (
<span>This field is required</span>
)}
<ReCAPTCHA
className="captchaStyle"
sitekey="obsf"
onChange={onChange}
onErrored={error}
badge={"bottomright"}
size={"invisible"}
ref={recaptchaRef}
/>
<input type="submit" />
</form>
</div>
</Item>
</React.Fragment>
)
})}
{close && <CartItems />}
</>
)
}
const WithLayout = Component => {
return props => (
<>
<Layout>
<Component {...props} />
</Layout>
...
</>
)
}
export default WithLayout(StoreDetails)
export const query = graphql`
query StoreDeatailsQuery($slug: String!) {
...
}
`
You are never populating the reference with any value. Initially is set to null in:
const recaptchaRef = React.createRef()
You have to wait for the Google response to fill the recaptchaRef with a value. In other words, you need to use a promise-based approach to fill it using an executeAsync() and using an async function:
const onSubmit = async (data) => {
const yourValue = await recaptchaRef.current.executeAsync();
console.log(yourValue)
}
You can check for further details about the props exposed in react-google-recaptcha documentation.

React: array as props shows as undefined

I'm trying to pass an array called myitems as props to a child component, but I get an error saying that options is undefined in the Child component. Not sure what's going on here. Any help will be highly appreciated.
Child component:
import React from 'react';
const Dropdown = ({className, options}) => {
return (
<>
<select className={className}>
{options.map((el,i) => (<option key={i}>{el.type}</option>))}
</select>
</>
)
}
export default Dropdown;
Parent component:
import React from 'react';
import Dropdown from './Dropdown'
const BudgetInput = ({ descValue, budgetValue, onDescChange }) => {
const myItems = [{ type: '+' }, { type: '-' }];
return (
<>
<Dropdown
className="add__type"
options={myItems}
/>
<input
type="text"
className="add__description"
placeholder="Add description"
value={descValue}
onChange={onDescChange}
/>
<input
type="number"
className="add__value"
placeholder="Value"
value={budgetValue}
//onChange={}
/>
<Dropdown
className="add__category"
/>
<button onClick={handleInput}>Enter</button>
</>
)
}
export default BudgetInput;
You're not passing an options prop to the second Dropdown instance, which is why you're getting the error
<Dropdown
className="add__category"
/>

Cannot read property 'props' of undefined in react, pass data from parent to child

I'm sitting with this for a while and wondering if there is any possibility of passing the state from parent to child in this case?
I need this id to give input and label an unique id couse this component is used multiple times.
Thanks for any advice.
Parent:
<FileUpload key={el.id} parentCallback={this.callback(el.id)} id={el.id}/>
Child:
import React, { Fragment, useState } from 'react';
import Message from './Message';
import Progress from './Progress';
import axios from 'axios';
const FileUpload = ({ parentCallback }) => {
return (
<Fragment>
<form className="image__uploadForm" onSubmit={onSubmit}>
{this.props.id} // Causes error props undef
<div className='image__upload'>
<input
type='file'
className='input__uploadFile'
id='uploadFile'
accept="image/*"
onChange={onChange}
/>
<label className='input__uploadFile--label' htmlFor='uploadFile'>
{filename}
</label>
{!file ? (
null
) :
<input
type='submit'
value='Upload'
/>
}
</div>
</form>
</Fragment>
);
};
export default FileUpload;
As #ajobi said, this will not be defined in a functional component using the arrow syntax.
You can solve this three ways:
1. Use the rest syntax to gather all props except parentCallback into a variable called props:
const FileUpload = ({ parentCallback, ...props }) => {
...
{props.id}
2. Spread all props into their own variables:
const FileUpload = ({ parentCallback, id }) => {
...
{id}
3. Spread none of the variables and use the props object when using all props in your component:
const FileUpload = (props) => {
...
{props.id}
...
props.parentCallback
You can not pass your callback like this parentCallback={this.callback(el.id)} because it will be executed instantly by render.
You could try to pass in an error function like parentCallback={() => this.callback(el.id)} and call it in the submit function
Id is undefined because Id is a key word and will be not passed
Parent:
<FileUpload key={el.id} parentCallback={() => this.callback(el.id)} {...el}/>
Child:
import React, { Fragment, useState } from 'react';
import Message from './Message';
import Progress from './Progress';
import axios from 'axios';
const FileUpload = ({ parentCallback, id }) => {
const onSubmit = () => {
return parentCallback()
}
return (
<Fragment>
<form className="image__uploadForm" onSubmit={onSubmit}>
{id}
<div className='image__upload'>
<input
type='file'
className='input__uploadFile'
id='uploadFile'
accept="image/*"
onChange={onChange}
/>
<label className='input__uploadFile--label' htmlFor='uploadFile'>
{filename}
</label>
{file && <input type='submit' value='Upload'/>} //Tip: If you work with && you do not need to return null
</div>
</form>
</Fragment>
);
};
export default FileUpload;
Otherwise you can pass your function like:
Parent:
<FileUpload key={el.id} parentCallback={this.callback} {...el}/>
Child:
....
const FileUpload = ({ parentCallback, id }) => {
const onSubmit = () => {
return parentCallback(id)
}
return (....)
}

Categories