Unable to pass function in props to a Component | React - javascript

I am trying to pass the function onSearchChangeEvent() from my App.js to Searchbox component as a function but I am getting the error saying
Expected onChange listener to be a function, instead got a value of
object type.
I looked up to different answers on Stackoverflow for the same error but I am unable to resolve this issue.
App.js : Contains the function onSearchChangeEvent() I am trying to pass to a < Searchbox /> component.
import React, {Component} from 'react';
import Cardlist from './Cardlist';
import Searchbox from './Searchbox';
import {robots} from './robots';
class App extends Component {
constructor () {
super()
this.state = {
robots : robots,
searchfield : ''
}
}
onSearchChangeEvent = () => {
console.log("Something Happened");
}
render () {
return (
<div className='tc'>
<h1>Robo Friends</h1>
<Searchbox searchChange={() => this.onSearchChangeEvent}/>
<Cardlist robots={this.state.robots} />
</div>
);
}
}
export default App;
Searchbox.js
import React from 'react';
const Searchbox = (searchField, searchChange) => {
return (
<div className='pa2'>
<input
className='pa3 ba b--green bg-lightest-blue'
type='search'
placeholder='Search Robots'
onChange={searchChange}
/>
</div>
);
}
export default Searchbox;
Error : First I get the warning, when the event is triggered I get the error

You aren't accessing the props correctly in SearchBox component. You would need to destructure them instead of defining them as arguments
const Searchbox = ({ searchField, searchChange }) => {
return (
<div className='pa2'>
<input
className='pa3 ba b--green bg-lightest-blue'
type='search'
placeholder='Search Robots'
onChange={searchChange}
/>
</div>
);
}
and pass it down like
<Searchbox searchChange={this.onSearchChangeEvent}/>
or
<Searchbox searchChange={() => this.onSearchChangeEvent()}/>
Though you must prefer <Searchbox searchChange={this.onSearchChangeEvent}/> since you are already using arrow function while defining onSearchChangeEvent function

Related

React How to get props from parent props in react-select Component

i have problem with react-select, when i want to get a value from the props of parent element in react select
import React from 'react'
import Select,{ components } from 'react-select'
import { FormLabel } from 'react-bootstrap'
const componentSelect = ({errors,...props}) => {
console.log(props) // return props of react-select component
console.log(errors) // this line return undefined
return (<div>
<components.Control {...props} />
<div className="invalid-feedback">Error {errors?.message}</div>
</div>)
};
and the react-select component like this:
export const StandardSelect = ({
options=[],
label,
key,
errors,
...props
})=>{
return (
<div className="form-group mb-3 " {...key || ''}>
<FormLabel>{label}</FormLabel>
<Select components={errors && {Control:componentSelect}} options={options}/>
</div>
)
}
how can i get the errors props from this :
export const StandardSelect = ({
options=[],
label,
key,
errors, //==>> this props <<==
...props
})=>{
into this component:
const componentSelect = ({errors,...props}) => {
console.log(props) // return props of react-select component
console.log(errors) // ==>> into this line expect return `errors` from `StandardSelect`<<===
return (<div>
<components.Control {...props} />
<div className="invalid-feedback">Error {errors?.message}</div>
</div>)
};
did you have any idea or solutions?
i'm so glad if you had :)
NB: for the good documentation the react-select, so componentSelect declared in the outside of StandardSelect scope. looks this docs react-select components defining
*sorry for my bad english :)

how do i pass a the input value of the textfield from some component to another component in reactjs?

I am trying to pass the value of the text area from some component in reactjs to be used in another react component. the component value is stored in the first component in a useState hook so I want to access it in another component and run map() function around it . Is this possible in reactjs ? I don't want to put the whole thing in app.js because that is just plain HTML which I don't want. I want to use reactjs function components instead ?
first component:
import React, { useState, useRef, useEffect } from "react";
function Firstcomp() {
const [quotes, setQuotes] = useState(["hi there", "greetings"]);
const reference = useRef();
function sub(event) {
event.preventDefault();
setQuotes((old) => [reference.current.value, ...old]);
console.log(quotes);
return;
}
return (
<>
<div>
<div>
<div>
<h4>jon snow</h4>
</div>
<form onSubmit={sub}>
<textarea
type="textarea"
ref={reference}
placeholder="Type your tweet..."
/>
<button type="submit">Tweet</button>
</form>
{quotes.map((item) => (
<li key={item}>{item}</li>
))}
{/* we can use card display taking item as prop where it
will do the job of filling the <p> in card entry */}
</div>
</div>
</>
);
}
export default Firstcomp;
second component
import React from "react";
function SecondComp(props) {
return (
<div>
<p>{props.message}</p>
</div>
);
}
export default Secondcomp;
Use a global management state like Recoil, Redux ot Context
import React from 'react';
export const UserContext = React.createContext();
export default function App() {
return (
<UserContext.Provider value="Reed">
<User />
</UserContext.Provider>
)
}
function User() {
const value = React.useContext(UserContext);
return <h1>{value}</h1>;
}
on the exemple above we used useContext hook to provide a global variable "value", even its not declared directly in User component, but you can use it by calling the useContext hook.
in this exemple the return value in the user component is "Reed"

How to modify react useState from secondary File

I'm all new to react and am currently trying to modify an useState hook from another File. When one of the radio buttons from "Options.tsx" get's selected, the result should somehow be updated with the setResult function of useState hook so the Tag gets updated.
I think I almost got it, but I don't manage to pass the correct 'onSelect' Property to Options.tsx so it is updated.
Here's my code so far:
App.tsx
import React from 'react';
import './App.css';
import { useState } from 'react';
import { Result, ResultType } from './Result'
import { Options } from './Options'
function App() {
const [result, setResult] = useState<ResultType>('pending')
return (
<div className="App">
<header className="App-header">
<Options onSelect={props.onSelect} />
<Result result={result} />
</header>
</div>
);
}
export default App;
Options.tsx
import React from 'react'
interface Props {
onSelect: (correct: boolean) => void
}
export const Options = ({onSelect}: Props) => {
// TODO
const setWrong = () => setResult('wrong');
const setCorrect = () => setResult('correct');
return(
<div>
<fieldset>
<input type='radio' id='option1' onSelect={setWrong}/>
<label htmlFor='option1'>Label 1</label>
<input type='radio' id='option2' onSelect={setCorrect}/>
<label htmlFor='option2'>Label 2</label>
<input type='radio' id='option3' onSelect={setCorrect}/>
<label htmlFor='option3'>Label 3</label>
</fieldset>
</div>
)
}
Result.tsx (just for completion - works fine so far)
import React from 'react'
export type ResultType = 'pending' | 'correct' | 'wrong'
interface Props {
result: ResultType
}
export const Result = ({ result }: Props) => {
switch (result) {
case 'pending':
return <h2>Make a guess</h2>
case 'correct':
return <h2>Yay, good guess!</h2>
case 'wrong':
return <h2>Nope, wrong choice...</h2>
}
}
Any idea, how I can update the useState from Options.tsx?
Thank you in advance!
It's quite simple - you just need to propagate the setter via properties, to Options.
<Options setResult={setResult} />
Or, provide your own method which uses setResult, depending on circumstances.
I would note though that the value you're currently passing down to the onSelect, appears to be bound to an incorrect value. Typescript compiler is probably complaining about it?
You can pass the updater function to Options component:
<Options setResult={setResult} />
then in your Options Component you can use
props.setResult('blah')
Just pass setResult prop to Options component.
App.tsx:
function App() {
const [result, setResult] = useState<ResultType>('pending')
return (
<div className="App">
<header className="App-header">
<Options onSelect={props.onSelect} setResult={setResult} />
<Result result={result} />
</header>
</div>
);
}
Options.tsx:
export const Options = ({onSelect, setResult}: Props) => {
const setWrong = () => setResult('wrong');
const setCorrect = () => setResult('correct');
...
}

How to pass props to custom components in react-select

I am trying to use a custom component as an input field in react-select. Since I need validation I am trying to use HTML5 oninvalid (onInvalid in JSX) for my input tag and set the custom message for oninvalid. However I am unable to pass the message as a prop to the component that I am setting in select. Below is my code.
Input.js
import React from "react";
import { components } from "react-select";
export default class Input extends React.Component {
constructor(props) {
super(props);
}
componentDidMount() {
console.log("component mounted");
}
setInvalidMessage = event => {
event.target.setCustomValidity("Custom Message");
};
render() {
if (this.props.isHidden) {
return <components.Input {...this.props} />;
}
return (
<components.Input
{...this.props}
required
onInvalid={this.setInvalidMessage}
/>
);
}
}
example.js
import React from "react";
import Input from "./Input";
import Select from "react-select";
import { colourOptions } from "./docs/data";
const InputBoxWithText = props => {
return <Input {...props} />;
};
export default () => (
<form>
<Select
closeMenuOnSelect={true}
components={{ InputBoxWithText }}
options={colourOptions}
/>
<input type="submit" />
</form>
);
If I pass Input in components attribute I get the hard coded message in Input.js. If I pass InputBoxWithText I don't see Input mounting at all.
index.js
import React from 'react';
import ReactDOM from 'react-dom';
import Example from './example';
ReactDOM.render(
<Example />,
document.getElementById('root')
);
Here is CodeSandBox.io URL.
Can any one let me know if what am I doing wrong.
It's better to pass custom props via select:
props.selectProps
To avoid re-creating of Custom component each time Select updates, what may cause unexpected bugs.
In my case I was passing errors in such way:
<Select
defaultValue={values}
selectProps={{ errors }}
isMulti
options={inventoryList}
onChange={changeTreeElement}
// #ts-ignore
styles={colourStyles}
/>
Then access it like selectProps.selectProps.errors in colourStyles methods.
I managed to pass my custom props using an arrow function
See docs for defining components
const Input = (inputProps: InputProps) => (
<components.Input {...inputProps} />
);
<Select
closeMenuOnSelect={true}
options={colourOptions}
components={{Input}}
/>
I don't have the solution (i'm looking for the same thing as well), but you example has multiple errors.
To load the input you have to write components={{ Input: InputBoxWithText }}, since the component name for Input is not InputBoxWithText.
Also the onInvalid does not seem to be part of the Input API, so it will never trigger. Are you trying to use the <input oninvalid="" />..?
In version 5 the only way to use custom props with typescript is to use module augmentation.
So in my project I opened react-app-env.d.ts and added there this:
import { GroupBase } from 'react-select'
declare module 'react-select/dist/declarations/src/Select' {
export interface Props<Option, IsMulti extends boolean, Group extends GroupBase<Option>> {
customOnClear: () => void;
}
}
You pass the prop to the select like this:
import Select from "react-select";
<Select customOnClear={() => {/* Your custom clear */} />
And use it in your custom component like this:
const ClearIndicator = ({ selectProps }: ClearIndicatorProps<Option, false>) => {
const { customOnClear } = selectProps
return <InputClear onClick={customOnClear} />
}
Docs:
https://react-select.com/typescript#custom-select-props

JSreact child component error

I edited code that was working perfectly fine, until I added new code to make the button clicking work from video to video. I just can't find the error, and the terminal is not picking it up either.
Can someone tell me why the ./video_list_item.js is not being recognized anymore?
Attached is the parent, and 2 child components, though I have 5 total components the error is definitely only in one of the two.
index.js
import React, {Component } from 'react';
import ReactDOM from 'react-dom';
import YTSearch from 'youtube-api-search';
import SearchBar from './components/searchbar';
import VideoList from './components/video_list';
import VideoDetail from './components/video_detail';
const API_KEY = 'AIzaSyAi1CzVpifuFUDVQf3dzrTu3mwJDP2n8r8';
class App extends Component {
constructor(props){
super(props);
//Do i expect this component to play any type of state? aka pass props
this.state= {
videos: [],
selectedVideo:null
};
// ^proper name can be anything
YTSearch({key: API_KEY, term: 'surfboards'}, (videos) => {
// console.log(data);
this.setState({ videos:videos,
selectedVideo: videos[0]
});
}); // this.setState({videos : vidoos});
}
render (){
return (
<div>
<SearchBar />
<VideoDetail video={this.state.selectedVideo} />
<VideoList
onVideoSelect={selectedVideo => this.setState({selectedVideo}) }
videos={this.state.videos} />
</div>
);
}
}
ReactDOM.render(<App />, document.querySelector('.container'));
video_list.js
//video list file. JS.react
import React from 'react';
import VideoListItem from './video_list_item';
const VideoList = (props) => {
// ^props is made args here because videos var is passed
// in index.js into VideoList function(with state).
const videoItems = props.videos.map((video) => {
return (
<VideoListItem
onVideoSelect={props.onVideoSelect}
key={video.etag}
video ={video} />
);
});
return (
<ul className="col-md-4 list-group">
{videoItems}
</ul>
);
};
export default VideoList;
video_list.item.js
//video list item file. JS.react
import React from 'react';
const VideoListItem = ({video, onVideoSelect}) => {
const imageUrl = video.snippet.thumbnails.default.url;
// can see this in console log
return (
<li onClick={() => onVideoSelect{video} }className="list-group-item">
<div className ="video-list media">
<div className ="media-left">
<img className="media-object" src = {imageUrl}/>
</div>
<div className="media-body">
<div className="media-heading"> {video.snippet.title} </div>
</div>
</div>
</li>
);
};
export default VideoListItem;
I can post the error message I get in the dev tools, but it literally just says one thing. This is the error message => Cannot find module "./video_list_item"
Also, no files were moved around at all, the code was edited and that created the error message. Thanks for anyone who sincerely answers this question!
<li onClick={() => onVideoSelect{video} }className="list-group-item">
The error is the {video} should actually be in parenthesis like so (video).
correct code is:
<li onClick={() => onVideoSelect(video) }className="list-group-item">.
Note: The {} makes it so the child component is not recognized by the parent for some strange reason. Thanks to all those who helped in answering!

Categories