I am working on a project with React for the first time. What I am trying to do is send a Child component's value that is within an input field to a variable in its Parent. More precisely, I would like the value to be transmitted whenever the value in the input field is changed. Here is a basic overview of what I have (simplified):
const Parent = () => {
const handleSubmit = (e) => {
e.preventDefault();
// Series of variables to hold the values from Child2
}
return (
<div>
<form onSubmit={handleSubmit}>
<div>
<Child1 name="child1"/>
<Child1 name="child2"/>
</div>
<button>Submit</button>
</form>
</div>
);
}
const Child1 = () => {
return (
<div>
<Child2 name="childchild1"/>
<Child2 name="childchild2"/>
<Child2 name="childchild3"/>
</div>
);
}
const Child2 = () => {
return (
<div>
<input type="number" .......></input>
</div>
);
}
In brief, my goal is to have the values from the input fields in the component Child2 to be transmitted to some array of values in Parent. That being said, I have looked at multiple ways of lifting up values in React online, but I haven't found something similar to my scenario. What would be the best way of proceeding? Thanks!
I think you can use useContext feature from react. so it is basically a way to manage state globally and you can share state between deeply nested components. so I'm thinking to make a function on the Parent that can be used from nested child to get value, you can use onChange method for instance
import { createContext, useContext } from "react";
const UserContext = createContext();
const Parent = () => {
const handleSubmit = (e) => {
e.preventDefault();
// Series of variables to hold the values from Child2
};
const handleInput = (data) => {
console.log(`this is data ${data.target.value}`);
};
return (
<UserContext.Provider value={handleInput}>
<div>
<form onSubmit={handleSubmit}>
<div>
<Child1 name="child1" />
<Child1 name="child2" />
</div>
<button>Submit</button>
</form>
</div>
</UserContext.Provider>
);
};
const Child1 = () => {
return (
<div>
<Child2 name="childchild1" />
<Child2 name="childchild2" />
<Child2 name="childchild3" />
</div>
);
};
const Child2 = () => {
const handleInput = useContext(UserContext);
return (
<div>
<input type="number" onChange={(e) => handleInput(e)}></input>
</div>
);
};
export default Parent;
perhaps this link can help you useContext
you can send a function from parent to child 1 then to child2, in this case we gonna send this function handleGetDataFromParent={getDataFromParent}
const Parent = () => {
const handleSubmit = (e) => {
e.preventDefault();
// Series of variables to hold the values from Child2
}
const getDataFromParent=(data)=>{
console.log('DATA from Child2', data)
}
return (
<div>
<form onSubmit={handleSubmit}>
<div>
<Child1 name="child1" handleGetDataFromParent={getDataFromParent}/>
<Child1 name="child2" handleGetDataFromParent={getDataFromParent}/>
</div>
<button>Submit</button>
</form>
</div>
);
}
const Child1 = ({handleGetDataFromParent}) => {
return (
<div>
<Child2 name="childchild1" handleGetDataFromParent={handleGetDataFromParent}/>
<Child2 name="childchild2" handleGetDataFromParent={handleGetDataFromParent}/>
<Child2 name="childchild3" handleGetDataFromParent={handleGetDataFromParent}/>
</div>
);
}
const Child2 = ({handleGetDataFromParent}) => {
const setNumber=(number)=>{
handleGetDataFromParent(number)
}
return (
<div>
<input type="number" onChange={(n)=>setNumber(n)}.......></input>
</div>
);
}
Related
I am working on a personal project in React for the first time. It has a structure of the following form (the following is simplified):
const Parent = () => {
const handleSubmit = (e) => {
e.preventDefault();
// Series of variables to hold the values from Child2
}
return (
<div>
<form onSubmit={handleSubmit}>
<div>
<Child1 name="child1"/>
<Child1 name="child2"/>
</div>
<button>Submit</button>
</form>
</div>
);
}
const Child1 = () => {
return (
<div>
<Child2 name="childchild1"/> // Child 2 components are individual inputs fields
<Child2 name="childchild2"/>
<Child2 name="childchild3"/>
</div>
);
}
const Child2 = () => {
return (
<div>
<input type="number" .......></input>
</div>
);
}
Basically put, I would like to add an import button in my Parent component which will fill the fields found in the Child2 Components. My question is: How would I go about passing the values from my Parent component to my Child2 Components so that they fill their input fields? I am looking for a relatively clean solution if possible. Thanks!
Component are build to be reusable. The clean way is to pass value from Child2 to Parent through Child 1.
const Parent = () => {
const [state1, setState1] = useState({})
const [state2, setState2] = useState({})
const handleSubmit = (e) => {
e.preventDefault();
// Series of variables to hold the values from Child2
}
return (
<div>
<form onSubmit={handleSubmit}>
<div>
<Child1 value={state1} onChange={setState1} name="child1"/>
<Child1 value={state2} onChange={setState2} name="child2"/>
</div>
<button>Submit</button>
</form>
</div>
);
}
const Child1 = ({ value, onChange }) => {
return (
<div>
<Child2 value={value.substate1} onChange={v=>onChange({...value, substate1: v})} name="childchild1"/> // Child 2 components are individual inputs fields
<Child2 value={value.substate2} onChange={v=>onChange({...value, substate2: v})} name="childchild2"/>
<Child2 value={value.substate3} onChange={v=>onChange({...value, substate3: v})} name="childchild3"/>
</div>
);
}
const Child2 = ({ value, onChange }) => {
return (
<div>
<input value={value} onChange={onChange} type="number" .......></input>
</div>
);
}
If that answer is unacceptable for you, you can have a look to redux or react context, but that breaks the reusability of the component and thats not "clean"
I'm having trouble passing data between two React siblings. I need to have an input component that will receive and pass the input to sibling that will handle the input and perform some logic.
I get to receive the data in the parent, but I cannot seem to get the passing to the sibling to work...
This is the wrapper/parent
const [corpBrandId, setCorpBrandId] = useState("");
const [secondInput, setSecondInput] = useState("");
const handleCorpBrandIdChange = ({ target }) => {
setCorpBrandId(target.value);
};
const handleSecondInputChange = ({ target }) => {
setSecondInput(target.value);
};
const handleClick = () => {
// console.log(corpBrandId);
// console.log(secondInput);
};
return (
<div className="App">
<InputField
label="Corporate brand ID "
onChange={handleCorpBrandIdChange}
value={corpBrandId}
/>
<TableConnect corpBrandId={corpBrandId} secondInput={secondInput} />
<InputField
label="Second input param"
onChange={handleSecondInputChange}
value={secondInput}
/>
<button onClick={handleClick}>Click me</button>
</div>
);
}
export default MainWrapper;
And here's the input component:
return (
<div>
<label>{label}</label>
<input type="text" value={value} name={name} onChange={onChange} />
</div>
);
};
export default InputField;
I've got no working or remotely close code how to receive the data...
This doesn't work in the sibling:
return (
<div>
Test
{props.corpBrandId}
{props.secondInput}
</div>
);
}
Anyone got any idea?
Based on your comment to #Shahar's answer, it sounds like you maybe haven't defined props in your TableConnect component. It should look something like this:
const TableConnect = (props) => {
return (
<div>
Test
{props.corpBrandId}
{props.secondInput}
</div>
);
};
Here's a codesandbox where TableConnect is correctly receiving the input from your input fields: https://codesandbox.io/s/throbbing-cloud-wgub8?file=/src/App.js
export default InputField;
return (
<div>
Test
{props.corpBrandInput} //shouldnt it be: corpBrandId
{props.inputText} //shouldnt it be: secondInput
</div>
);
}
What is the preferred way to change state in React using Hooks?
Option 1: I think this is the more "traditional"
function App() {
const [input, setInput] = useState('');
const onInputChange = (event) => {
setInput(event.target.value)
};
return (
<div className='App'>
<Form onInputChange={onInputChange} />
</div>
);
}
const Form = ({ onInputChange }) => {
return (
<div>
<div>
<div>
<input
type='text'
onChange={onInputChange}
/>
<button'>
Submit
</button>
</div>
</div>
</div>
);
};
export default Form;
Option 2: But I have seen people do this
function App() {
const [input, setInput] = useState('');
return (
<div className='App'>
<Form onInputChange={setInput} />
</div>
);
}
export default App;
const Form = ({ onInputChange }) => {
return (
<div>
<div>
<div>
<input
type='text'
onChange={(e) => {
onInputChange(e.target.value);
}}
/>
<button>
Submit
</button>
</div>
</div>
</div>
);
};
export default Form;
In Option 1 in the App component the logic to change it's state is there.
In Option 2, the logic to change App component is in a child component, right?
If I understand correctly, I think Option 1 makes more sense. What do you think?
option 1 is better because we only have to pass the props or data to child component not the logic , Logic must be reside in parent component.
Hello i have an component where i set a prop darkMode in a useState. I want to give this to the child component with onDarkmodeChange={darkMode}. This child gave this prop also to his child. In the toggle switch i want to use the prop onDarkmodeChange. But how am i supposed to use this? I tink i am doing something wrong because darkMode is not updated anymore.
export function PageLayout({ children }) {
const [darkMode, setDarkMode] = React.useState(false)
return (
<Header onDarkModeChange={darkMode} />
)
}
export function Header({ onDarkModeChange }) {
return (
<ToggleSwitch {... { onDarkModeChange }} />
)
}
export function ToggleSwitch({ onDarkModeChange }) {
const [isToggled, setIsToggled] = React.useState(onDarkModeChange)
return (
<label className={styles.component}>
<input className={styles.input} type='checkbox' checked={isToggled} onChange={() => setIsToggled(!isToggled)} />
<span className={cx(styles.switch, isToggled && styles.isActive)} />
</label>
)
}
I think it's not necessary to have the isToggled state since it's going to have the same value that the darkMode state. Also, I would move all the logic to the parent so that both children can access and manipulate that state, in case that it's necessary. Try this:
export function PageLayout({ children }) {
const [darkMode, setDarkMode] = React.useState(false)
const switchDarkMode = () => {
setDarkMode(currentDarkMode => !currentDarkMode)
}
return (
<Header darkMode={darkMode} switchDarkMode={switchDarkMode} />
)
}
export function Header({ darkMode, switchDarkMode }) {
return (
<ToggleSwitch darkMode={darkMode} switchDarkMode={switchDarkMode} />
)
}
export function ToggleSwitch({ darkMode, switchDarkMode }) {
return (
<label className={styles.component}>
<input className={styles.input} type='checkbox' checked={darkMode} onChange={switchDarkMode} />
<span className={cx(styles.switch, darkMode && styles.isActive)} />
</label>
)
}
I have a parent component that has a button with an onClick event and when there is an error I want to focus on an input that is in a child component. I know this can be done using useRef but I keep getting an undefined error. Here is my code:
/* Parent Component */
const parent = () => {
const acresRef = useRef();
const addrRef = useRef();
const acresFocus = () => {
acresRef.current.focus();
};
const addressFocus = () => {
addrRef.current.focus();
};
return (
<Child addrRef={addrRef} acresRef={acresRef} />
<button onClick={acresFocus} />
<button onCLick={addressFocus} />
)
}
/*Child Component*/
const Child = forwardRef(
({props}, acresRef, addrRef) => (
<div>
<label for="address">Address</label>
<input type="text" name="address" ref={addrRef} />
</div>
<div>
<label for="acres">Acres</label>
<input type="text" name="acres" ref={acresRef} />
</div>
)
);
You are incorrectly using refs here. forwardRef works when ref is passed to the component. Anything apart from that is a prop to the component. So in your case, acresRef and addrRef will be received within props by the child component.
/*Child Component*/
const Child = (props) => (
<>
<div>
<label htmlFor="address">Address</label>
<input type="text" name="address" ref={props.addrRef} />
</div>
<div>
<label htmlFor="acres">Acres</label>
<input type="text" name="acres" ref={props.acresRef} />
</div>
</>
);
/* Parent Component */
const Parent = () => {
const acresRef = React.useRef();
const addrRef = React.useRef();
const acresFocus = () => {
acresRef.current.focus();
};
const addressFocus = () => {
addrRef.current.focus();
};
return (
<>
<Child addrRef={addrRef} acresRef={acresRef} />
<button onClick={acresFocus}>acres</button>
<button onClick={addressFocus}>address</button>
</>
);
};
Check this codesandbox here.
You may also just bind the props like so :
const Child = (props) => {
const onClick = props.onClick;
return(<div><p>
{onClick()}
</p>
</div>
);
}
/* Parent Component */
const ParentEl = () => {
const onClick = ()=>{return "hi"};
return (
<div>
<Child onClick={onClick} />
</div>
)
}
/*Child Component*/
export default function App() {
return (
<div className="App">
<ParentEl />
<h1>Hello CodeSandbox</h1>
<h2>Start editing to see some magic happen!</h2>
</div>
);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
or a codesandbox link to see directly what it does :
https://codesandbox.io/s/hidden-water-s8qjj?file=/src/App.js
here :
const onClick = props.onClick;
in the child component is doing all the magic