skip to Main Content

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


  1. 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

    const [newSubstance, setNewSubstance = useState("")
    
    return (
       <>
          <SubstanceForm newSubstance={newSubstance} setNewSubstance={setNewSubstance} />
          <PreviousSearches substances={substances} newSubstance={newSubstance} deleteSubstance={deleteSubstance} />
       </>
     )
    

    SubstanceForm.jsx

    export function SubstanceForm({ newSubstance, setNewSubstance }) {
        return (<>
            <form>
                <input
                  type="text"
                  value={newSubstance}
                  onChange={e => setNewSubstance(e.target.value)}
                />
                <button type="submit">Search</button>
            </form>
        </>)
    }
    

    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.

    Login or Signup to reply.
  2. 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.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search