Tengo un componente simple <StatefulView> que mantiene un estado interno. Tengo otro componente <App> que alterna si <StatefulView> se representa o no.
Sin embargo, quiero mantener el estado interno de <StatefulView> entre el montaje y el desmontaje.
Pensé que podría crear una instancia del componente en <App> y luego controlar si está renderizado/montado.
var StatefulView = React.createClass({ getInitialState: function() { return { count: 0 } }, inc: function() { this.setState({count: this.state.count+1}) }, render: function() { return ( <div> <button onClick={this.inc}>inc</button> <div>count:{this.state.count}</div> </div> ) } }); var App = React.createClass({ getInitialState: function() { return { show: true, component: <StatefulView/> } }, toggle: function() { this.setState({show: !this.state.show}) }, render: function() { var content = this.state.show ? this.state.component : false return ( <div> <button onClick={this.toggle}>toggle</button> {content} </div> ) } }); Aparentemente, esto no funciona y se crea un nuevo <StatefulView> en cada alternancia.
Aquí hay un JSFiddle .
¿Hay alguna manera de conservar el mismo componente después de desmontarlo para poder volver a montarlo?
Dado que no puede mantener el estado en el componente mismo cuando se desmonta, debe decidir dónde más debe guardarse.
Estas son tus opciones:
Si está buscando una solución fácil en la que los datos se mantengan fuera de React, este Hook podría ser útil:
const memoryState = {}; function useMemoryState(key, initialState) { const [state, setState] = useState(() => { const hasMemoryValue = Object.prototype.hasOwnProperty.call(memoryState, key); if (hasMemoryValue) { return memoryState[key] } else { return typeof initialState === 'function' ? initialState() : initialState; } }); function onChange(nextState) { memoryState[key] = nextState; setState(nextState); } return [state, onChange]; }Uso:
const [todos, setTodos] = useMemoryState('todos', ['Buy milk']);ESTÁ BIEN. Entonces, después de hablar con un grupo de personas, resulta que no hay forma de guardar una instancia de un componente. Por lo tanto, TENEMOS que guardarlo en otro lugar.
1) El lugar más obvio para guardar el estado es dentro del componente principal.
Esta no es una opción para mí porque estoy tratando de enviar y abrir vistas desde un objeto similar a UINavigationController.
2) Puede guardar el estado en otro lugar, como una tienda Flux, o en algún objeto global.
Esta tampoco es la mejor opción para mí porque sería una pesadilla hacer un seguimiento de qué datos pertenecen a qué vista en qué controlador de navegación, etc.
3) Pase un objeto mutable para guardar y restaurar el estado.
Esta fue una sugerencia que encontré al comentar en varios tickets de emisión en el repositorio Github de React. Este parece ser el camino a seguir para mí porque puedo crear un objeto mutable y pasarlo como accesorios, luego volver a renderizar el mismo objeto con el mismo accesorio mutable.
De hecho, lo he modificado un poco para que sea más generalizado y estoy usando funciones en lugar de objetos mutables. Creo que esto es más sensato: los datos inmutables siempre son preferibles para mí. Esto es lo que estoy haciendo:
function createInstance() { var func = null; return { save: function(f) { func = f; }, restore: function(context) { func && func(context); } } } Ahora en getInitialState estoy creando una nueva instancia para el componente:
component: <StatefulView instance={createInstance()}/> Luego, en StatefulView , solo necesito guardar y restaurar en componentWillMount y componentWillUnmount .
componentWillMount: function() { this.props.instance.restore(this) }, componentWillUnmount: function() { var state = this.state this.props.instance.save(function(ctx){ ctx.setState(state) }) }Y eso es. A mí me funciona muy bien. Ahora puedo tratar los componentes como si fueran instancias :)
Para aquellos que solo están leyendo esto en 2019 o más allá, ya se han dado muchos detalles en las otras respuestas, pero hay un par de cosas que quiero enfatizar aquí: