I wanna use react make act system like android activity system
following it's my code, the bug is I have set actE's state k:"v", but final line app.setState({act: actE}) cause actE state k: null, why actE state is reset?
class Act extends PureComponent<any, { k: string }> {
constructor(props: any, context: any) {
super(props, context)
this.state = {
k: null
}
}
render() {
return this.state.k
}
}
class Act2 extends Act {
}
class App extends PureComponent<any, { act: ReactElement }> {
constructor(props: any, context: any) {
super(props, context)
this.state = {
act: null
}
}
render() {
return this.state.act;
}
}
var app: App
ReactDOM.render(<App ref={e => app = e}/>, document.querySelector("#root"))
var act: Act
let actE = <Act ref={(e) => {
if (e) {
act = e
}
}}/>
app.setState({act: actE})
act.setState({k: "v"})
var act2: Act2
var act2E = <Act2 ref={(e) => {
if (e) {
act2 = e
}
}}/>
app.setState({act: act2E})
act2.setState({k: "v2"})
app.setState({act: actE})
I actually missed this line initially. So i thought you are managing "hidden" components.
return this.state.act;
But actually you are trying to mount actE and then act2E and then back to actE. ok. Your code essentially translate to something like this in a normal React code.
const actE = <Act ref={ref} />, act2E = <Act ref={ref2} />
return flag ? actE : act2E
After actE is unmounted, what happened to the stuff inside?
The problem is the following line.
let actE = <Act ref={(e) => {
if (e) {
act = e
}
}}/>
You can't use a if here. Because if you do that, you miss the unmount. act in the above code is supposed to be null after unmount. And React want to make sure none of the internal is exposed anymore after that.
To be honest, you should wonder why your computer hasn't been frozen yet because your code should produce a memory leak ;)
My tmp solution is cache reused reactElement's state and instance vars, when reuse reactElement, manually set the cache
following is my code:
class Act extends PureComponent<any, { k: string }> {
constructor(props: any, context: any) {
super(props, context)
this.state = {k: null}
}
k2: string
render() {
return `${this.state.k} ${this.k2}`
}
}
class Act2 extends Act {
}
class App extends PureComponent<any, { act: ReactElement }> {
constructor(p: any) {
super(p)
this.state = {act: null}
}
render() {
return this.state.act
}
}
var parentKeys = Object.keys(new PureComponent({}))
var app: App
var act: Act
/**
* reactElement is replace will be unmounted, for ex, my following code act2E instead actE, actE will be unmounted, if I wanna reuse actE, I should cache it's 'state' and instance vars
* @param act
*/
var getCache = (act: any) => {
var keyVal: any = {}
var keys = Object.keys(act).filter((e) => {
return !parentKeys.includes(e)
})
keys.forEach((key) => {
if (key != "state" && !key.match(/^_react/i)) { // should use special meth #setState to set, _react I don't need it
keyVal[key] = act[key]
}
})
return {keyVal: keyVal, state: act.state}
}
var setCache = (newAct: any, actCache: any) => {
for (var [k, v] of Object.entries(actCache.keyVal)) {
newAct[k] = v
}
act.setState(actCache.state)
act.forceUpdate()
}
var actE = <Act ref={(e) => {
act = e
}}/>
var act2: Act2
var act2E = <Act2 ref={(e) => {
act2 = e
}}/>
testReact(<App ref={e => app = e}/>)
app.setState({act: actE})
act.setState({k: "v"})
act.k2 = "k2"
var actCache = getCache(act)
app.setState({act: act2E})
act2.setState({k: "v2"})
app.setState({act: actE})
setCache(act, actCache)