Estoy tratando de actualizar (setState) un componente funcional de React desde JavaScript "regular" (vainilla).
Busqué a través de StackOverflow, pero todas las respuestas se ocupan de pasar datos de React a JavaScript (vainilla), y no al revés.
Tomemos el ejemplo de los documentos :
import React, { useState } from 'react'; function Example() { // Declare a new state variable, which we'll call "count" const [count, setCount] = useState(0); return ( <div> <p>You clicked {count} times</p> <button onClick={() => setCount(count + 1)}> Click me </button> </div> ); }Para renderizarlo en JavaScript, hago:
let example = ReactDOM.render( <Example />, document.getElementById('example-wrapper') );Ahora supongamos que quiero actualizar manualmente el conteo desde el código JavaScript estándar, fuera de reaccionar. Me gusta:
function updateExampleCount(newCount) { example.setCount(newCount); // ??? } No puedo acceder al estado del componente, ya que setCount es una variable privada dentro de la función, y el example devuelto por render es null .
Si uso un componente de clase, render devuelve una referencia al componente y luego puedo llamar a example.setState . Pero prefiero no convertir mi componente en una clase si puedo evitarlo.
Los documentos para render dicen :
Procesa un elemento React en el DOM en el contenedor proporcionado y devuelve una referencia al componente (o devuelve un valor nulo para los componentes sin estado).
Pero mi componente tiene un estado (recuento), simplemente no lo reconoce. Si no es posible usar el valor de retorno de render , ¿hay otra forma de "obtener" el componente y luego usar setCount (o alguna otra forma de establecer el estado)?
¿O solo tengo que usar un componente de clase para esto?
Gracias.
Es posible. Podría pasar su función setCount como parámetro para usarla en su JS fuera de React, pero realmente no lo recomendaría.
Recomendaría que mantenga su lógica comercial y la lógica de React separadas.
Lo único que debe conocer el estado y lo usará son los propios componentes de React. Estructuraría su código de manera que no esté acoplado a React, y no tenga que usar o depender del estado de React de ninguna manera.
Esto es más fácil decirlo que hacerlo al principio. Si necesita ayuda con eso, tal vez proporcione un caso de uso que está tratando de resolver de esta manera, y se podría proporcionar una mejor respuesta.
No hay forma de acceder al estado desde fuera del componente. Es como tratar de acceder a una variable de ámbito local desde fuera de una función.
El uso de un componente de clase tampoco ayudaría, ya que no podría obtener la instancia de la clase creada dentro de la aplicación React.
Si desea desencadenar un cambio de estado desde fuera de la aplicación, la aplicación debe proporcionar un controlador de eventos.
Para (un muy rápido y sucio) ejemplo:
const outside = { value: 2, callbacks: [], addCallback: function (callback) { this.callbacks.push(callback); }, setValue: function (value) { this.value = value; this.callbacks.forEach( callback => callback(this.value) ); } }; function Component = () => { const [val, setVal] = useState(outside.value); useEffect(() => { outside.addCallback((value) => setVal(value)); }, []); return <p>{val}</p> }Se puede hacer extendiendo Example para que pase una referencia a la función setCount de vuelta al código principal, vea a continuación. (Esto podría ser lo mismo que mencionó Oli, si es así, entonces tuve la misma idea e hice una implementación funcional antes de responder)
const { useState } = React; // functionFromComponent will store the function from Example. let functionFromComponent = undefined; const setter = (someFn) => functionFromComponent = someFn; const Example = ({ setFunction }) => { // take `setFunction` from props const [count, setCount] = useState(0); setFunction(setCount); // pass setCount to the parent code return ( <div> <p>You clicked {count} times</p> <button onClick={() => setCount(count + 1)}> Click me </button> </div> ); } ReactDOM.render( <Example setFunction={setter} />, document.getElementById('example-wrapper') ); function buttonClicked() { if (functionFromComponent) { functionFromComponent(777); } } <script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.1/umd/react.production.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.1/umd/react-dom.production.min.js"></script> <div id="example-wrapper"></div> <button id="regularButton" onclick="buttonClicked()">Regular button</button>