Fondo
Tengo un formulario simple de 3 pasos de ReactJS que los consumidores usan para solicitar soporte técnico de nuestros socios.
Hasta ahora, el formulario de solicitud de soporte era universal para todos nuestros socios (nombre, correo electrónico, problema)
Ahora, me gustaría para un socio específico, agregar elementos de formulario adicionales. Idealmente, esto debería ser personalizable por socio. Por ejemplo, el socio A desea capturar también el número de serie del dispositivo. Al socio B le gustaría que el cliente aceptara los términos del servicio.
Para resolver esto, paso un componente opcional a mi formulario. Si está allí, se representa. No he descubierto cómo acceder a los datos de los componentes opcionales y pasarlos como un campo de datos opaco como parte del envío de la solicitud.
Pregunta
En el siguiente código, en Form , ¿cómo puedo acceder al estado de FormOverride ?
O, ¿hay una forma más idomática de lograr lo que estoy buscando?
A diferencia de una jerarquía padre/hijo donde un padre puede acceder al estado secundario de varias maneras, el componente FormOverride se instancia fuera de la jerarquía del Form y se pasa como una propiedad.
import React from "react"; const Form = ({ override }) => { //universal form state const handleSubmit = () => { if (override) { //get the state value from override component } alert("Clicked"); }; return ( <> <h3>Contact Info</h3> {override} <h3>Support Details</h3> <h3>Case Summary</h3> <button onClick={handleSubmit}>Submit</button> </> ); }; const FormOverride = () => { const [text, setText] = React.useState(""); const handleChange = (e) => { setText(e.target.value); }; return ( <div> <input type="text" value={text} onChange={handleChange} /> </div> ); }; export default function App() { const someValue = "composed"; let toRender = null; if (someValue === "default") { toRender = <Form/>; } if (someValue === "composed") { toRender = <Form override=<FormOverride /> />; } return <div className="App">{toRender}</div>; }En tales casos, un administrador de estado global como Redux es útil, pero puede implementarlo sin un administrador de estado global con la técnica state lift up (como mencionó en los comentarios), pero de una manera complicada:
Implementemos un estado en el componente de la App y pasémoslo a los componentes relacionados:
export default function App() { const [textOverride, setTextOverride] = React.useState(""); const someValue = "composed"; let toRender = null; if (someValue === "default") { toRender = <SomeComponent />; } if (someValue === "composed") { toRender = ( <SomeComponent override={<ComposedValue getOverrideText={setTextOverride} />} textOverride={textOverride} /> ); } return <div className="App">{toRender}</div>; } Como puede ver, los accesorios getOvverideText se pasaron a ComposedValue , por lo que debemos llamarlo cuando cambie la entrada.
const ComposedValue = ({ getOverrideText }) => { const [text, setText] = React.useState(""); const handleChange = (e) => { const value = e.target.value; setText(value); getOverrideText(value); }; return ( <div> <input type="text" value={text} onChange={handleChange} /> </div> ); }; Ahora, el valor textOvveride (que definimos en la App ) está actualizado con los cambios de entrada de texto. por lo que podemos usar fácilmente el valor textOverride en SomeComponent como se muestra a continuación:
const SomeComponent = ({ override, textOverride }) => { const handleSubmit = () => { if (override) { //get the state value from override component } alert(textOverride); }; return ( <> <h3>Contact Info</h3> {override} <h3>Support Details</h3> <h3>Case Summary</h3> <button onClick={handleSubmit}>Submit</button> </> ); }; Nota: Prefiero usar un Global State Manager como Redux para hacer tales cosas, ya que la implementación anterior es difícil de depurar y cambiar. El lado malo de esta implementación es que SomeComponent se volverá a renderizar con cada cambio en el elemento de input .
Nota: no hay forma de obtener overrideText al llamar a la función handleSubmit porque no hay componentes padre-hijo. Pero, con el uso de herramientas como Redux, puede ignorar la nueva representación adicional y obtener overrideText al mismo tiempo que llama a la función handleSubmit .
Nota: Supongo que simplificó los componentes para demostrar su propósito; de lo contrario, usar un elemento de input independiente dentro de SomeComponent reducirá los códigos y el procedimiento para obtener los cambios de otro componente.