-
Notifications
You must be signed in to change notification settings - Fork 27
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
returning null in a view #201
Comments
no. domvm's current architecture assumes a 1:1 vdom:dom relationship: every vnode has a representation in the dom and every view must return exactly one vnode. it's up to the parent whether a view is part of its children. |
FWIW, in my experience I've never found this to be a significant limitation; and I have some pretty sophisticated apps using DOMVM. |
if you're interested in a view persisting after unmount, you can always use |
I'm playing around with creating a component/view based router like React Router. If a path doesn't match I was hoping to return It'd be nice to return |
in React, does returning null have equivalent behavior to the parent never including the component (it gets unmounted and destroyed (loses all state))? |
I don't think it so. But I'd have to test it. |
Looks like it keeps state. https://codesandbox.io/s/pk4yq52pmj |
i'm not sure it demonstrates maintaining state of unmounted components since you're just using passed-down props. what i mean is if this does not work: import React, { Component } from "react";
class Test extends Component {
state = {
count: 0
}
componentDidMount() {
console.log(`I am mounted ${this.props.msg} ${this.state.count++}`);
}
componentWillUnmount() {
console.log(`I unmounted ${this.props.msg}`);
}
render() {
const { toggleRender } = this.props;
return toggleRender ? <div>hi</div> : null;
}
}
export default Test; this means an unmounted component always destroys any state, including when it returns null (which looks equivalent to not including it in the parent). so even though it's in the vtree, React destroys its state, along with it DOM if null is returned, right? if this is the case, it's confusing to me. i would expect component that i maintain in the vtree across renders to continue to live, even if its dom is destroyed and un-rendered. |
I'm pretty sure it holds the state. https://codesandbox.io/s/pk4yq52pmj yes, when the component unmounts it's state is destroyed. when the component returns |
ah, ok. i'll give this some thought. it's not a quick fix, but i see how it's useful and better than create & inject, though i do wonder if that can be made into something similar without modifying the core. i don't see anything in https://reacttraining.com/react-router/web/example/basic that can't be replicated with a bit of js and domvm. this "maintaining view state despite unmounting in a declarative way" seems to be the thorny part. would be interesting to do a proof of concept with createView, injectView and vm memoization to simulate this. it's certainly possible, though the ergonomics could be anywhere on the scale from not-too-bad to wtf. |
Just another perspective: I often have sub-views whose life-cycle is best managed declaratively. Those sub-views then need to pull data once they are initialized, and it doesn't make sense to render the content until the data is fetched, except for maybe a loading indicator. Here's what I currently do: function SomeView(vm) {
let data;
vm.config({
didMount() {
fetch('/remote/data').then(_data => {
data = _data;
vm.redraw();
});
}
});
return function() {
if (!data) return el('div.some-view');
return el('div.some-view', [
// view content
])
}
} .some-view:empty { display: none } I've often thought it would be nice if I could return other views directly and simply use the parent as a controller, or have a promise delayed mount similar to the unmount feature. |
fwiw we moved to React from mithril at my work and I've found being able to return |
this is a far bigger undertaking than handling
i agree that this would be a good quality of life improvement rather than creating/using a create/injectView manager. but again, i'd like to see what this solution would look like before committing to modifying the core. |
@iamjohnlong am I correct in understanding that returning null is really only useful for a single level? if i have App -> Component1 -> Component2 and Component 1 returns null, then Component2 and its state is completely lost. e.g.: https://codesandbox.io/s/lyzvk98w7l if using domvm's imperative views, it's possible to retain view state at every level: https://jsfiddle.net/oLxhp148/ var el = domvm.defineElement;
var vw = domvm.defineView;
var iv = domvm.injectView;
var cv = domvm.createView;
var showB = true;
var showC = true;
function ViewA() {
var i = 0;
var vmB = cv(ViewB);
return () =>
el("div", [
"ViewA " + i++,
showB && iv(vmB),
]);
}
function ViewB() {
var i = 0;
var vmC = cv(ViewC);
return () =>
el("div", [
"ViewB " + i++,
showC && iv(vmC),
]);
}
function ViewC() {
var i = 0;
return () =>
el("div", "ViewC " + i++);
}
var vmA = cv(ViewA).mount(document.body);
setTimeout(() => {
showB = false;
vmA.redraw();
}, 2000);
setTimeout(() => {
showB = true;
showC = false;
vmA.redraw();
}, 4000);
setTimeout(() => {
showC = true;
vmA.redraw();
}, 6000); |
Yes I believe so.
Rad. It doesn't have anything to do with returning |
Allow me to disagree. DISCLAIMER: I'm not a React user, so plz correct me where i'm wrong. The only method React provides of retaining local component state across mounts/unmounts is by keeping that component in the vtree. There is no possibility of declaratively excluding it from the parent to temporarily unmount it. This makes returning Currently, domvm is built on a simple principle: if it's in the vtree, it's in the dom; if it's not in the vtree, it's not in the dom. Additionally, domvm provides the ability to retain local component state across mounts/unmounts beyond that of React without having to keep things in the vtree simply for retention purposes. I believe that domvm's retention facilities are both clearer and more powerful than what React provides (as demonstrated in the above fiddle). Certainly, I'm not interested in implementing things simply because React does them and they're useful (or necessary) in React-land with its particular limitations / design choices / quirks. Back in the context of routing. In React, if returning null is only useful for retaining a single level of local component state, then what does that mean for nested routes? Is all of their state retained in the parents? In a global store? In the router? Do all components become functional and stateless? Sorry for turning a seemingly simple thing into a philosophical rant 😬 |
I'm not asking for that. If the As far as your other questions I'm not sure. There are several ways to handle state in react and I'm not going to try to explain them here. |
my hope is that this discussion yields some use-cases with a clear benefit to returning null - where the alternative is really ugly or counter-intuitive. if the only thing that null returns would provide is to allow sub-components to handle their own mounting/unmounting logic w/state retention (but only 1 level deep), then this would not be a good fit for domvm. |
Yeah I'm not sure it would make sense to allow multi level state retention and where/how that would be handled? |
one use case that comes to mind is nested tabs in an admin interface, each with local state. possibly with nested routes. I see only two use cases for null returns:
To be honest, neither of these is compelling enough to warrant the addition (which is not a one-liner, and needs handling added in multiple places in the codebase). The fact that state can already be retained by existing and uniform So it's not a matter of when multi-level local state retention could be useful, but rather what benefit |
I personally prefer the createView/injectView explicit semantics as well. I would find returning null to achieve that very "magical". |
probably the most ergonomic way to achieve a near-equivalent of a var el = domvm.defineElement;
var cm = domvm.defineComment;
var vw = domvm.defineView;
var cv = domvm.createView;
var vis = true;
function AppView(vm) {
return function() {
return el("#app", [
vw(SubView)
]);
};
}
function SubView() {
var i = 0;
setInterval(function() {
i++;
}, 200);
return function() {
return vis ? el("div", "abc " + i) : cm("SubView " + i);
};
}
var vm = cv(AppView).mount(document.body);
setTimeout(function() {
vis = false;
vm.redraw();
}, 3000);
setTimeout(function() {
vis = true;
vm.redraw();
}, 6000); |
Returning null throws errors, is there a way not to return a root node?
The text was updated successfully, but these errors were encountered: