Home > OS >  Is there a better way to access variables from one React component to another than just passing it t
Is there a better way to access variables from one React component to another than just passing it t

Time:11-02

Let's say I have a React component somewhat like this:

function App() {
  const [step, setStep] = useState(0);
  const [someValue, setSomeValue] = useState("xyz");
  const var1 = "abc";
  const var2 = "def";

  function StepZero() {
    return <div>
       <p>{someValue}</p>
       <input type="text" id="fname" name="fname" />
       <h1>{var1} {var2}</h1>
       <Button onClick={() => setSomeValue("123")}>Click</Button>
     </div>;
  }
  
  function StepOne() {
    return <div>
      <h1>{someValue}</h1>
      <Button onClick={() => setSomeValue("456")}>Click</Button>
      <h2>{var1}</h2>
      <h3>{var2}</h3>
    </div>;
  }

  return (
    <div>
        {step === 0 ? (
          <StepZero />
        ) : (
          <StepOne />
        )}
    </div>
  );
}

What happens here is, once someValue gets set, the whole StepZero gets re-rendered and the input lost. Really any user interaction gets reset, e.g. an accordion that got opened. What resolves this is putting StepZero and StepOne directly into the return function, or putting them outside the App component and then passing all the variables in the params like:

{ var1, var2, someValue, setSomeValue }

Is there a better way to do this that I can separate the two steps into components while still being able to access the states and variables/constants, without state changes re-rendering the components every time, or without having to pass all the required variables as parameters?

Note this example app isn't meant to do anything functionally useful

CodePudding user response:

Based on react architecture passing states and variables through props is the best solution.

Now, based on what you requested I have multiple suggestion:

  • if the constants are resetting, have you tried to save the constants in a ref? (for ex: const var1 = useRef("abc");)

  • if you don't want to pass data as props but you want them to share the same variables, you can either add Redux (React-redux) or use React Context (How to use React Context)

  • But if you're project isn't big, i'd suggest you pass them as props, similar to the following:

In the parent App component:

 const [step, setStep] = useState(0);
  const [someValue, setSomeValue] = useState("xyz");
  const var1 = useRef("abc");
  const var2 = useRef("def");

And in a separate component

      function StepZero({someValue,var1,var2,setSomeValue}) {
    return <div>
       <p>{someValue}</p>
       <input type="text" id="fname" name="fname" />
       <h1>{var1.current} {var2.current}</h1>
       <Button onClick={() => setSomeValue("123")}>Click</Button>
     </div>;
  }

CodePudding user response:

First all your child components have to be outside your App function, in order of having their own state. Secondly you will pass the somevalue state to all your child in a props and lift the state up to your parent with a callback function.

https://reactjs.org/docs/lifting-state-up.html

Something like this (I simplified your code for the example)

function StepZero({val,var1,var2,callback}) {
    return <div>
       <p>{val}</p>
       <input type="text" id="fname" name="fname" />
       <h1>{var1} {var2}</h1>
       <Button onClick={() => callback("123")}>Click</Button>
     </div>;
  }

function App() {
  const [step, setStep] = useState(0);
  const [someValue, setSomeValue] = useState("xyz");
  const var1 = "abc";
  const var2 = "def";
  return (
    <div>        
       <StepZero val={someValue} var1={var1} var2={var2} callback={setSomeValue} />        
    </div>
  );
}

CodePudding user response:

I think you need to know more about how reactjs its work, and base on that you can go...the main idea you need start think about that react is Component-Based, and thats mean "Build encapsulated components that manage their own state"

so, from this point you can know that we have component which its has a control to manage their state, so this will move to next step..

At first level, we have props, state and context, which all of these concepts will help you to pass/share data

1- Props will used to pass data from higher component to nested component, and its immutable

2- State will track your value change and you can updated it to update needed functions...

3- Context which its used to share data between multiple component without passing a props from higher one to lowest one...

After we know about these details, we need to go to step two, which we need to understand Re-render... The render spitted to initial render which happens when a component first appears on the screen and re-render happens when React needs to update the app with some new data, and usually its happen base on action or interactive action... Note: react handle the re-render and know which spesfic part is render and handling to re-render it, its virtual dom and can be controlled very well...

Now lets go to your code:

1- You can pass your details as props, and you can split App component to small component:

function StepZero(props) {
        return <div>
           <p>{props.someValue}</p>
           <input type="text" id="fname" name="fname" />
           <h1>{var1} {var2}</h1>
           <Button onClick={() => props.setSomeValue("123")}>Click</Button>
         </div>;
      }
      
      function StepOne(props) {
        return <div>
          <h1>{props.someValue}</h1>
          <Button onClick={() => props.setSomeValue("456")}>Click</Button>
          <h2>{var1}</h2>
          <h3>{var2}</h3>
        </div>;
      }

function App() {
      const [step, setStep] = useState(0);
      const [someValue, setSomeValue] = useState("xyz");
      const var1 = "abc";
      const var2 = "def";
    
      return (
        <div>
            {step === 0 ? (
              <StepZero {youProps}/>
            ) : (
              <StepOne {youProps}/>
            )}
        </div>
      );
    }

The second solution is use content React Context

For re-render you need to handling update dependency correctly and if its in loop or list you need to add key Also, you must know that var1 and var2 will keep re-render since its set direct without state, ref and its put directly in component not a static / const out side the component, so each time you re-render the component its will has a new memory address which its mean a new re-render for any place has lisen to it...

  • Related