I’m new to using React and have built a simple Vite + React app. It has a search form where where users can search substance names, and see a history of previous searches which are held in Local Storage.
The App.jsx
is very simple in that it renders 2 components like this:
return (
<>
<SubstanceForm onSubmit={addSubstance} />
<PreviousSearches substances={substances} deleteSubstance={deleteSubstance} />
</>
)
I understand the basics of how to use props and have managed to do that as shown above.
The problem I’m facing is that I want the user to be able to click on a previous search from the <PreviousSearches>
component, populate that value into a form field inside <SubstanceForm>
and re-run my search.
I read React – Change state in child component from another child component but the accepted answer says
This application sounds like the perfect use case for "Lifting State Up", i.e. holding the main state in the parent component.
I’ve seen numerous examples of the above but was curious if it’s possible to do without modifying the parent component, App.jsx
, at all?
In SubstanceForm.jsx
I have:
export function SubstanceForm({ onSubmit }) {
const [newSubstance, setNewSubstance] = useState("")
return (<>
<form onSubmit={handleSubmit}>
<input type="text"
value={newSubstance}
onChange={e => setNewSubstance(e.target.value)}
/>
<button type="submit">Search</button>
</form>
</>)
}
As you can see the value
attribute of the search input is equal to newSubstance
. It’s possible to update the state within the same component with setNewSubstance
.
I want to be able to do something like this in PreviousSearches.jsx
:
<a href="#" onClick={() => setNewSubstance({searchCriteria}) }>{searchCriteria}</a>
In this case {searchCriteria}
refers to a value (search keywords) of a previous search which is held in Local Storage. This is accessible inside PreviousSearches.jsx
. However setNewSubstance
is not accessible because it’s in the other component (SubstanceForm.jsx
).
Is there any way to call setNewSubstance
from PreviousSearches.jsx
?
The linked SO post seems to suggest modifying App.jsx
and then handle all state through that. That seems quite convoluted especially as the app grows. Is there a way you can modify state in one child component from another without any reliance on changing the parent component?
2
Answers
You can indeed update the state right from within the child components, but you will need to pass a state variable declared on your parent component to it. Here’s what you can do:
App.jsx
SubstanceForm.jsx
If you don’t want to involve the parent component at all, then you’d need some global state management like Redux. In your example your parent component is already the
App.jsx
– basically the highest component, which is why I reckon to go with simply passing a parent-defined state variable and its setter function to the children.In React, directly updating state in one child component from another without involving the parent is challenging due to the "one-way data flow" principle. This ensures data flows down from parent to child, making applications more predictable.
However, if you really want to avoid modifying App.jsx as a parent, you can go through few alternative approaches:
Context API: You can create a context to hold shared state (like newSubstance) and the setter function (setNewSubstance). Both SubstanceForm and PreviousSearches can then access and modify this shared state, bypassing the need to lift the state into App.jsx.
Custom Hook: Another way is to create a custom hook to manage the newSubstance state. This can be imported and used by both components without needing to modify App.jsx.