I am trying to understand how to share hooks state across components. But it doesn't seem to be sharing. Am I doing something wrong here?
Home.js
export default function Home() {
const [search, setSearch]= useState('');
return (
<div>
<Input search={search} handleChange={setSearch} />
<Products search={search} handleChange={setSearch} />
</div>
)
}
Input.js
export default function Input({search, setSearch}) {
const handleChange = (e) => {
setSearch(e.target.value)
}
return (
<div className='App'>
<input
placeholder='search...'
value={search}
onChange={handleChange}
/>
{search}
</div>
)
}
Live Example:
const { useState } = React;
/*export default*/ function Home() {
const [search, setSearch]= useState('');
return (
<div>
<Input search={search} handleChange={setSearch} />
<Products search={search} handleChange={setSearch} />
</div>
)
}
/*export default*/ function Input({search, setSearch}) {
const handleChange = (e) => {
setSearch(e.target.value)
}
return (
<div className='App'>
<input
placeholder='search...'
value={search}
onChange={handleChange}
/>
{search}
</div>
)
}
const Products = ({search}) => {
return <div>Product: {search}</div>;
};
ReactDOM.createRoot(document.getElementById("root"))
.render(<Home />);
<div id="root"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.0.0/umd/react.development.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.0.0/umd/react-dom.development.js"></script>
You pass handleSearch as prop in your Home component but Input is expecting setSearch, so just change this line in your Home
return (
<div>
<Input search={search} setSearch={setSearch} /> // change here
<Products search={search} handleChange={setSearch} />
</div>
)
Related
I am trying to learn ReactJS API and want to achive the parent-child but it still doesn't work and I can't find the criteria that I want in those videos.
What I've tried by watching tutorials:
import './App.css';
import Axios from 'axios'
import { useState } from 'react';
function App() {
const [pokeName, setPokeName] = useState("")
const [ability, setAbillity] = useState("")
const data = () => {
Axios.get(`https://pokeapi.co/api/v2/pokemon/${pokeName}`).then((res) => {
console.log(res.data)
setAbillity(res.data)
})
}
return (
<div className="App">
<input placeholder='name of pokemon...' onChange={(event) => {setPokeName(event.target.value.toLowerCase())}} />
<br />
<br />
<button onClick={data}>Click</button>
<br />
<br />
<br />
<h1>Abilities: {ability.power}
</h1>
</div>
);
}
export default App;
Try with pikachu, charizard
const App = () => {
const [pokeName, setPokeName] = React.useState("")
const [ability, setAbillity] = React.useState([])
const data = () => { fetch(`https://pokeapi.co/api/v2/pokemon/${pokeName}`)
.then((res) => res.json())
.then((res) => {
setAbillity(res.abilities)
})
}
return (
<div className="App">
<input placeholder='name of pokemon...' onChange={(event) => {setPokeName(event.target.value.toLowerCase())}} />
<br />
<br />
<button onClick={data}>Click</button>
<br />
<br />
<br />
<h1>Abilities: {ability.map(item => item.ability.name).join(", ")}
</h1>
</div>
)
}
ReactDOM.render(
<App />,
document.getElementById('root')
);
<script src="https://unpkg.com/react#16.7.0-alpha.0/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom#16.7.0-alpha.0/umd/react-dom.development.js"></script>
<div id="root"></div>
I have a ready-made form in React
I'm trying to add a captcha to it but it would seem that with the only correct option the captcha reload infinity loops
I didt think that in such a simple task in React there could be so many problems
import { GoogleReCaptchaProvider, GoogleReCaptcha } from 'react-google-recaptcha-v3'
type Props = {
onSubmit: (values: AuthRequest) => Promise<AuthResponse>
}
function AuthForm(props: Props) {
const [token, setToken] = useState('')
return (
<div className={cn('container')}>
<GoogleReCaptchaProvider reCaptchaKey="[key]">
<Form
onSubmit={handlers.submit}
render={({ handleSubmit }) => (
<form onSubmit={handleSubmit}>
<FormField name={'email'} />
<div>
<FormField name={'password'} />
</div>
<GoogleReCaptcha
onVerify={(token) => {
setToken(token)
}}
/>
<div>
<Button type="submit">Submit</Button>
</div>
</form>
)}
/>
</GoogleReCaptchaProvider>
</div>
)
}
export { AuthForm }
I solved it like this
import { GoogleReCaptchaProvider, GoogleReCaptcha } from 'react-google-recaptcha-v3'
type Props = {
onSubmit: (values: AuthRequest) => Promise<AuthResponse>
}
function AuthForm(props: Props) {
const [token, setToken] = useState('')
const verifyRecaptchaCallback = React.useCallback((token) => {
setToken(token)
}, []);
return (
<div className={cn('container')}>
<GoogleReCaptchaProvider reCaptchaKey="[key]">
<Form
onSubmit={handlers.submit}
render={({ handleSubmit }) => (
<form onSubmit={handleSubmit}>
<FormField name={'email'} />
<div>
<FormField name={'password'} />
</div>
<GoogleReCaptcha
onVerify={verifyRecaptchaCallback}
/>
<div>
<Button type="submit">Submit</Button>
</div>
</form>
)}
/>
</GoogleReCaptchaProvider>
</div>
)
}
export { AuthForm }
I have a parent component and a child component.
The parent component sends data to the child.
The child modifies the value and the parent should see the change reflected.
But nevertheless there is something that I am not doing well because I do not understand the mechanisms of react well.
Parent component
function ParentComponent() {
var userName = "Didi";
return (
<div className="Parent">
<label>Parent - {userName}</label>
<ChildComponent userName={userName} />
</div>
);
}
Child component
function ChildComponent({ userName }) {
const handleChange = (e) => {
userName = e.target.value;
};
return (
<div className="ChildComponent">
<input type="text" defaultValue={userName} onChange={handleChange} />
<br />
<label>ChildComponent - {userName}</label>
</div>
);
}
React can't monitor free variables for changes. You need to store data in a state (or use some external system like Redux).
If you want to change the state from a different component, then you need to pass the function which changes it to the component.
function ParentComponent() {
const [userName, setUserName] = React.useState("Didi");
return (
<div className="Parent">
<label>Parent - {userName}</label>
<ChildComponent userName={userName} setUserName={setUserName} />
</div>
);
}
function ChildComponent({ userName, setUserName }) {
const handleChange = (e) => {
setUserName(e.target.value);
};
return (
<div className="ChildComponent">
<input type="text" defaultValue={userName} onChange={handleChange} />
<br />
<label>ChildComponent - {userName}</label>
</div>
);
}
Try this:
Parent component
function ParentComponent() {
const [username, setUsername] = useState("");
return (
<div className="Parent">
<label>Parent - {username}</label>
<ChildComponent
username={username}
changeUsername={value => setUsername(value)}
/>
</div>
);
}
Child component
function ChildComponent({ username, changeUsername }) {
const handleChange = e => {
changeUsername(e.target.value);
};
return (
<div className="ChildComponent">
<input type="text" value={username} onChange={handleChange} />
<br />
<label>ChildComponent - {username}</label>
</div>
);
}
You have to do this:
Parent component
import {useState} from 'react';
function ParentComponent() {
const [userName,setUserName]=useState("Didi");
return (
<div className="Parent">
<label>Parent - {userName}</label>
<ChildComponent userName={userName} setUserName={setUserName}/>
</div>
);
}
Child component
function ChildComponent({ userName,setUserName }) {
return (
<div className="ChildComponent">
<input type="text" defaultValue={userName} onChange={(e)=>setUserName(e.target.value)} />
<br />
<label>ChildComponent - {userName}</label>
</div>
);
}
I am trying to set the value inside an input in a Form component using KendoReact but the value is not displayed and upon debugging I see that the value is not defined. What am I doing wrong and what is the right approach here? Here is my code:
import * as React from 'react';
import * as ReactDOM from 'react-dom';
import { Form, Field, FormElement } from '#progress/kendo-react-form';
import { Input } from '#progress/kendo-react-inputs';
const InputField1 = (fieldRenderProps) => {
const { label, value } = fieldRenderProps;
return (
<div>
<Input label={label} value={value} />
</div>
);
};
const App = () => {
return (
<div>
<Form
render={(formRenderProps) => (
<>
<br />
<br />
<div>
<Field
name="Field1"
label="Field1 Label"
component={InputField1}
value="value1"
/>
</div>
<br />
<br />
</>
)}
/>
</div>
);
};
ReactDOM.render(<App />, document.querySelector('my-app'));
Here is a working codesandbox You have to pass the other props to the Input:
const InputField1 = (fieldRenderProps) => {
const { label, value, ...others } = fieldRenderProps;
console.log(value);
return (
<div>
<Input label={label} value={value} {...others} />
</div>
);
};
const MyCustomInput = (fieldRenderProps) => {
const {label, value, onChange} = fieldRenderProps;
return (
<Input label={label} value={value} onChange={onChange} />
);
};
const App = () => {
const handleSubmit = (dataItem) => alert(JSON.stringify(dataItem, null, 2));
return (
<Form
onSubmit={handleSubmit}
render={(formRenderProps) => (
<FormElement style={{maxWidth: 650}}>
<Field name={'firstName'} label={'First Name'} component={MyCustomInput} />
<div className="k-form-buttons">
<button type={'submit'} disabled=
{!formRenderProps.allowSubmit} className={'k-button'}>
Submit
</button>
</div>
</FormElement>
)}
/>
);
};
ReactDOM.render(
<App />,
document.querySelector('my-app')
);
you have to add onChange in input tag
I'm trying to fetch data from an API based on the year parameter with the initial year set to 2020. The components are on the same .jsx page and exported to App.js. When I try to log "search" it returns an empty object.
export default function Rank() {
const [ search, setSearch ] = useState(2020)
console.log(search)
return (
<main>
<div>
<SearchBar onSubmit={setSearch} />
</div>
<div>
<FetchTable />
</div>
</main>
);
}
I've removed some unrelated code in the FetchTable function but basically, it should return a table with data of the selected year.
function FetchTable(search) {
console.log(search)
useEffect(() => {
fetch(`exampleapiurl?year=${search}`)
function SearchBar(props) {
const [ innerSearch, setInnerSearch ] = useState();
return (
<div>
<input
aria-labelledby="search-button"
name="search"
id="search"
type="search"
value={innerSearch}
onChange={(e) => setInnerSearch(e.target.value)}
/>
<button
id="search-button"
type="button"
onClick={() => props.onSubmit(innerSearch)}
>
Search
</button>
</div>
)
}
Any help greatly appreciated.
You need to pass the search parameter to the FetchTable, and get it from the props. See comments in code.
const { useState, useEffect } = React
function Rank() {
const [search, setSearch] = useState(2020)
return (
<main>
<div>
<SearchBar onSubmit={setSearch} />
</div>
<div>
{/* pass search to FetchTable */}
<FetchTable search={search} />
</div>
</main>
)
}
function FetchTable({ search }) { // get search from the props
useEffect(() => {
// fetch(`exampleapiurl?year=${search}`)
console.log(search)
}, [search]) // useEffect should depend on search
return (
<div>{search}</div>
)
}
function SearchBar({ onSubmit }) {
const [innerSearch, setInnerSearch] = useState(''); // set an initial value to the state, so the input would be controlled
return (
<div>
<input
aria-labelledby="search-button"
name="search"
id="search"
type="text"
value={innerSearch}
onChange={(e) => setInnerSearch(e.target.value)}
/>
<button
id="search-button"
type="button"
onClick={() => onSubmit(innerSearch)}
>
Search
</button>
</div>
)
}
ReactDOM.render(
<Rank />,
root
)
<script crossorigin src="https://unpkg.com/react#17/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom#17/umd/react-dom.development.js"></script>
<div id="root"></div>