Passing Props With Input - React - javascript

Within a child component I have state to store input.
My goal is to pass the input state to the parent component.
//Child component
const [userInput, setUserInput] = useState("");
<TextField value={input} onInput={e => setInput(e.target.value)} />
I tried creating a function to be called on input within the parent function but I cannot seem to get the value "input" passed. What is the correct way to do this? Thanks!

you were approaching correctly. You can pass a function to get the data from the child to the parent. Check this example:
import { useState } from "react";
import "./styles.css";
export default function App() {
const [text, setText] = useState("");
const getInput = (t) => {
console.log(t);
setText(t);
};
return (
<div className="App">
<Component getInput={getInput} value={text} />
<p>{text}</p>
</div>
);
}
const Component = ({ getInput, value }) => {
return (
<>
<h1> Test </h1>
<input type="text" value={value} onChange={(e) => getInput(e.target.value)}></input>
</>
);
};
The parent App is retrieving the text from the child Component passing the function getInput. You only have to decide with event you want to detonate. Of course, this is with input not with TextField. I think that you are using TextField from React Material UI, if that's the case you may check the docs to know how to trigger an event.

You can move the state to the parent component. Then pass the props from the child to the parent.
function Child({
...rest
}) {
return <TextField {...rest} />
}
function Parent() {
const [input, setInput] = useState(''); // '' is the initial state value
return (
<Child value={value} onInput={e => setInput(e.target.value)} />
)
}

I finally figured this out.
// This is in the parent component
const [userInput, setUserInput] = useState("");
// Step 1: Create a function that handles setting the state
const inputHandler = (userInput) => {
setUserInput(userInput);
}
<PhaseTwoTemplate onInput={inputHandler} />
//Step 2: Add a function that calls the handler
...
// This is the child component PhaseTwoTemplete.js
const [input, setInput] = useState("");
// This second state holds the input data for use on child component
// It also is an easy way to hold the data for the parent function.
<TextField
onChange={e => setInput(e.target.value)}
value={input}
onInput={onInputHandler}
/>
// Step 3: Pass the user input to the parent
const onInputHandler = () => {
props.onInput(input);
}

Related

How can i place values of mapped input element in a state array on the parent element

I have two components, the parent(name Parent) and child(name Child), on the parent, i map an array and render the child, so the child appears like 4 times(number of times the child is displayed based on the mapping), i have an input field on the Child component (which will be 1 input field for the rendered child component), i am basically trying to get the values of the input field from all the rendered Child component (4 been rendered based on the mapping) and then send it to my parent component (store it in a state on the parent component).
mock code
parent component
const Items = [1,2,3,4]
export const Parent= () => {
return (<div>
{Items.map((Item, index) => {
return (
<div key={index}>
<Child />
</div>
);
})}
</div>
)
}
child component
export const Child = () => {
const [Amount, setAmount] = useState();
return (
<input
value={Amount}
onChange={(e) => setAmount(e.target.value)}
placeholder="Amount"
/>
)
}
sorry for the bad code formatting.
This is a mock of what it looks like
this should give a somewhat clear understanding or image of the issue, i basically want to get all the Amount on the 4 render children, place it in an array and send it to the Parent component (so i can call a function that uses all the amount in an array as an argument)
i tried to set the values of the Child component to a state on context (it was wrong, it kept on pushing the latest field values that was edited, i am new to react so i didnt understand some of the things that were said about state lifting
Congratulations, you've discovered the need for the Lifting State Up React pattern. Lift the "amount" state from the child component up to the parent component. The parent component holds all the state and provides it and a callback function down to children components via props.
Example:
import { useState } from "react";
import { nanoid } from "nanoid";
const initialState = Array.from({ length: 4 }, (_, i) => ({
id: nanoid(),
value: i + 1
}));
const Child = ({ amount, setAmount }) => {
return (
<input
value={amount}
onChange={(e) => setAmount(e.target.value)}
placeholder="Amount"
/>
);
};
const Parent = () => {
const [items, setItems] = useState(initialState);
const setAmount = (id) => (amount) =>
setItems((items) =>
items.map((item) =>
item.id === id
? {
...item,
value: amount
}
: item
)
);
return (
<div>
{items.map((item) => (
<Child
key={items.id}
amount={item.value}
setAmount={setAmount(item.id)}
/>
))}
</div>
);
};
try following method:
const Items = [1, 2, 3, 4];
export default function Parent() {
return <Child items={Items} />;
}
export function Child(props) {
const [childItems, setChildItems] = useState(props.items);
const handleChange = (e, index) => {
let temp = childItems;
temp[index] = e.target.value;
setChildItems(temp);
};
return (
<div>
{childItems.map((item, index) => {
return (
<div key={index}>
<input
value={item}
onChange={(e) => handleChange(e, index)}
placeholder="Amount"
/>
</div>
);
})}
</div>
);
}```

React Native TextInput not updating state in a functional component using onhange

I am using a in a react native functional component and onChange the state does not seem to be updating for "name".
I am console logging the new state using useEffect to check whether or not the state is updated and it is returning undefined as if the input text was never set as the state "name"
function AddTask () {
const [name, setName] = useState('');
useEffect(() => {
console.log(name),name;
})
const updateTaskInfo = event => setName(event.target.value);
return (
<TextInput
onChange={updateTaskInfo}
placeholder="Name"
value={name}
/>
);
}
export default AddTask;
use onChange like that event.nativeEvent.target.value
<TextInput onChange={ event => setName(event.nativeEvent.target.value) } />
or use onChangeText like that
<TextInput onChangeText ={ value => setName(value ) } />

Passing onChange from parent overides onChange of the child component - React

Let's say I have an Input component with onChange event handler in it, say count input characters(just to illustrate there's a build-in functionality in that component that I want to use no matter what) and I want to use this Input like across all of my other components:
const Input = (props) => {
const { name, value, countLimit, ...restProps } = props;
const [count, setCount] = useState(0);
const countCharacters = (e) => {
setCount(e.currentTarget.value.length);
};
return (
<div>
<input
name={name}
value={value}
onChange={countCharacters}
{...restProps}
/>
<br />
Count: {count} / {countLimit}
</div>
);
};
The problem though, is that if I want to pass an onChange event handler from outside this component, say to grab some input's value or pass some data from child to parent or something else, it will override this countCharacters one. What is the best way to deal with this kind of scenarios?
Invoke props.onChange (if it exists) from within countCharacters:
const Input = (props) => {
const { name, value, countLimit, onChange, ...restProps } = props;
const [count, setCount] = useState(0);
const countCharacters = (e) => {
setCount(e.currentTarget.value.length);
onChange?.(e);
};
return (
<div>
<input
name={name}
value={value}
onChange={countCharacters}
{...restProps}
/>
<br />
Count: {count} / {countLimit}
</div>
);
};

Passing data to sibling components with react hooks?

I want to pass a variable username from sibling1 component to sibling2 component and display it there.
Sibling1 component:
const sibling1 = ({ usernameData }) => {
// I want to pass the username value I get from input to sibling2 component
const [username, setUsername] = useState("");
const handleChange = event => {
setUsername(event.target.value);
};
return (
<Form.Input
icon='user'
iconPosition='left'
label='Username'
onChange={handleChange}
/>
<Button content='Login' onClick={handleClick} />
)
}
export default sibling1;
Sibling2 component:
export default function sibling2() {
return (
<h1> Here is where i want to display it </h1>
)
}
You will need to handle your userName in the parent of your siblings. then you can just pass setUsername to your sibling1, and userName to your sibling2. When sibling1 use setUsername, it will update your parent state and re-render your sibling2 (Because the prop is edited).
Here what it looks like :
const App = () => {
const [username, setUsername] = useState('Default username');
return (
<>
<Sibling1 setUsername={setUsername} />
<Sibling2 username={username} />
</>
)
}
const Sibling2 = ({username}) => {
return <h1> Helo {username}</h1>;
}
const Sibling1 = ({setUsername}) => {
return <button onClick={setUsername}>Set username</button>;
}
In parent of these two components create a context where you will store a value and value setter (the best would be from useState). So, it will look like this:
export const Context = React.createContext({ value: null, setValue: () => {} });
export const ParentComponent = () => {
const [value, setValue] = useState(null);
return (
<Context.Provider value={{value, setValue}}>
<Sibling1 />
<Sibling2 />
</Context.Provider>
);
Then in siblings you are using it like this:
const Sibling1 = () => {
const {setValue} = useContext(Context);
const handleChange = event => {
setValue(event.target.value);
};
// rest of code here
}
const Sibling2 = () => {
const {value} = useContext(Context);
return <h1>{value}</h1>;
}
best way: React Context + hooks
you can use React Context. take a look at this example:
https://codesandbox.io/s/react-context-api-example-0ghhy

set state is not updating state

I am trying to use the state hook in my react app.
But setTodos below seems not updating the todos
link to my work: https://kutt.it/oE2jPJ
link to github: https://github.com/who-know-cg/Todo-react
import React, { useState } from "react";
import Main from "./component/Main";
const Application = () => {
const [todos, setTodos] = useState([]);
// add todo to state(todos)
const addTodos = message => {
const newTodos = todos.concat(message);
setTodos(newTodos);
};
return (
<>
<Main
addTodos={message => addTodos(message)}
/>
</>
);
};
export default Application;
And in my main.js
const Main = props => {
const input = createRef();
return (
<>
<input type="text" ref={input} />
<button
onClick={() => {
props.addTodo(input.current.value);
input.current.value = "";
}}
>
Add message to state
</button>
</>
);
};
I expect that every time I press the button, The setTodos() and getTodos() will be executed, and the message will be added to the todos array.
But it turns out the state is not changed. (still, stay in the default blank array)
If you want to update state of the parent component, you should pass down the function from the parent to child component.
Here is very simple example, how to update state with hook from child (Main) component.
With the help of a button from child component you update state of the parent (Application) component.
const Application = () => {
const [todos, setTodos] = useState([]);
const addTodo = message => {
let todosUpdated = [...todos, message];
setTodos(todosUpdated);
};
return (
<>
<Main addTodo={addTodo} />
<pre>{JSON.stringify(todos, null, 2)}</pre>
</>
);
};
const Main = props => {
const input = createRef();
return (
<>
<input type="text" ref={input} />
<button
onClick={() => {
props.addTodo(input.current.value);
input.current.value = "";
}}
>
Add message to state
</button>
</>
);
};
Demo is here: https://codesandbox.io/s/silent-cache-9y7dl
In Application.jsx :
You can pass just a reference to addTodos here. The name on the left can be whatever you want.
<Main addTodos={addTodos} />
In Main.jsx :
Since getTodo returns a Promise, whatever that promise resolves to will be your expected message.
You don't need to pass message as a parameter in Main, just the name of the function.
<Main addTodos={addTodos} />
You are passing addTodos as prop.
<Main
addTodos={message => addTodos(message)}
/>
However, in child component, you are accessing using
props.addTodo(input.current.value);
It should be addTodos.
props.addTodos(input.current.value);

Categories

Resources