简体   繁体   中英

Manage many inputs between sibling components in React - best approach?

I am new to this topic.

In the parent component App I have two siblings: SideMenu and Document

The idea is that the user inputs values (SideMenu) which will be renedered on the Document. There will be more than 20 inputs. Since this is the first time I do this sort of state management, what are the best or maybe easiest approaches for this attempt of project.

function App() {
const [fullName, setFullName] = useState("")
const [address, setAddress] = useState("")
  return (
      <div className='app'>
        <SideMenu />
        <Document />
      </div>
  )
}
export default App 
const SideBar = () => {
  return (
    <div>
      <div className='input-group'>
        <label>Full Name:</label>
        <input type='text' />
      </div>
      <div className='input-group'>
        <label>Address:</label>
        <input type='text' />
      </div>
    </div>
  )
}
const Document = () => {
  return (
    <div>
      <h1>{fullName}</h1>
      <p>{address}</p>
    </div>
  )
}

You can use Formik library for handling many inputs. Wrap both components inside Formik and use formik's methods.

import { Formik } from 'formik';

     <Formik
       initialValues={{ fullName: '', address: '' }}
       onSubmit={(values) => {
           alert(JSON.stringify(values, null, 2));
       }}
     >
       {({handleChange, values, handleSubmit}) => (
         <form onSubmit={handleSubmit}>
           <div className='app'>
               <SideMenu 
                  handleChange={handleChange} 
               />
               <Document values={values} />
           <button type="submit">Submit</button>
         </form>
       )}
     </Formik>

You dont need to create multiple states for each input. handlChange will handle itself. You just need add name or id attribute to input. Also you can access values of each input using the values parameter like values.fullName .

const SideBar = ({handleChange}) => {
  return (
    <div>
      <div className='input-group'>
        <label>Full Name:</label>
        <input 
          type='text' 
          onChange={handleChange}
          name="fullName"
        />
      </div>
      <div className='input-group'>
        <label>Address:</label>
        <input 
          type='text' 
          onChange={handleChange} 
          name="address"
        />
      </div>
    </div>
  )
}

const Document = ({values}) => {
  return (
    <div>
      <h1>{values.fullName}</h1>
      <p>{values.address}</p>
    </div>
  )
}

There are a few approaches you can take to manage state in this situation:

  • You can pass the state values from the parent component to the child components as props, and then use them to render the data in the child components. This means that you would need to pass the fullName and address state values from the parent component to the Document component as props.

  • You can use a state management library like Redux to manage your global state and allow you to access the state values from any component in your application.

  • You can use the React Context API to create a context that stores the state values, and then use a context consumer in the child components to access the state values.

Which approach you choose will depend on the complexity of your application and your personal preferences . In general, if you have a small application with only a few state values, it's usually easier to just pass the state values as props . However, if you have a larger application with many state values that need to be shared across multiple components, it may be more appropriate to use a state management library or the Context API .

  1. Using Redux for this kind of situation is a huge anti-pattern. Redux global store should be only used for global state, not local form state.

  2. Context API is well suited when you need to pass data to multiple deeply nested children. This way you do not need to pass props dozens of levels down the tree.

  3. In any other case (ie the one in discussion) I suggest to use a container component that controls your form inputs state. Just pass them down one level by props and everything should be ok, simple and predictable.

You can create an object for your form and store the form inputs in this object. Shared state can be stored in the most closest and common component (in your situation this is your parent component) according to your child components. [1]

When you make an update from a child component other child component that is sharing state will be syncronized and your state will be updated. You shouldn't use redux like state management tools unless you are need to set a global state.

I have made a revision for your example, this scenario allows you to pass the state in the parent component to the child components and update the state in the parent component from the child components.

I used a common event handler in the parent component, this functions captures the html event and we parse this event and update the state via this function. [2][3]

import "./styles.css";
import { useState } from "react";

import SideBar from "./SideBar";
import Document from "./Document";

export default function App() {
  const [values, setValues] = useState({
    fullName: "",
    address: "",
    postalCode: ""
  });

  function handleChange(event) {
    setValues({ ...values, [event.target.name]: event.target.value });
  }

  return (
    <div className="app">
      <SideBar values={values} setValues={handleChange} />
      <Document values={values} setValues={handleChange} />
    </div>
  );
}
export default function Document({ values }) {
  return (
    <div>
      <h1>Document</h1>
      <p>Full Name: {values.fullName}</p>
      <p>Address: {values.address}</p>
      <p>Postal Code: {values.postalCode}</p>
    </div>
  );
}
export default function Sidebar({ setValues }) {
  return (
    <div>
      <div className="input-group">
        <label>Full Name:</label>
        <input type="text" name="fullName" onChange={setValues} />
      </div>
      <div className="input-group">
        <label>Address:</label>
        <input type="text" name="address" onChange={setValues} />
      </div>
      <div className="input-group">
        <label>Address:</label>
        <input type="text" name="postalCode" onChange={setValues} />
      </div>
    </div>
  );
}

Code Sandbox Link: https://codesandbox.io/s/stackoverflow-74961591-wpmcnd

[1]: Passing Props to a component: https://beta.reactjs.org/learn/passing-props-to-a-component

[2]: Updating Objects in State: https://beta.reactjs.org/learn/updating-objects-in-state

[3]: HTML Change Event: https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/change_event

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM