I am trying to use the Substrate UI to display the functionalities that are available in my run-time module. The code is written in React. I am trying to create a component that will help me track all the previous states of a structure.
The runtime.template.assets(i)
call takes a hex value i
as input and returns a structure kitty
which has a key parent_hash
(having a hex value). I want the while
loop to execute till I have reached a special hex value which in this case is "0x11da6d1f761ddf9bdb4c9d6e5303ebd41f61858d0a5647a1a7bfe089bf921be9"
which I have converted to String
to achieve the termination condition.
Please ignore the <KittyShrieks>
tag because it is something that I am using to display some values in the UI. Basically I am unable to do this inside the while loop
var kitty = await runtime.template.kitties(i);
.
.
i = kitty.parent_hash;
The required code
export class TrackCards extends ReactiveComponent {
constructor(props) {
super(['hash'])
}
unreadyRender() {
return <span>Nothing to track</span>
}
async readyRender() {
let kitties = [];
var i = this.state.hash;
var root_hash = "0x11da6d1f761ddf9bdb4c9d6e5303ebd41f61858d0a5647a1a7bfe089bf921be9";
var root = "17,218,109,31,118,29,223,155,219,76,157,110,83,3,235,212,31,97,133,141,10,86,71,161,167,191,224,137,191,146,27,233";
var iter = 0;
var a;
while ((root != i.toString()) {
var kitty = await runtime.template.kitties(i);
kitties.push(
<div className="column" key={i}>
<KittyShrieks
owner_count = {runtime.template.kittyHistoryCount(i)}
hash_original = {this.state.hash}
/>
</div>
);
i = kitty.parent_hash;
}
return <div className="ui stackable six column grid">{kitties}</div>;
}
}
I don't think using async render is a valid thing, but I am doing that because I seem to have no choice but to use the await keyword
. So, the problem is that the UI doesnot load and I get the following error:
Uncaught Invariant Violation: Objects are not valid as a React child (found: [object Promise]). If you meant to render a collection of children, use an array instead.
The UI loads fine if I remove async
keyword, var kitty = await runtime.template.kitties(i);
statement and insert a break
statement at the end of the loop. Therefore, disallowing me to iterate through the loop.
I am kind of new to React and even Javascript in general. Any kind of help would be appreciated.
A component always needs to be able to render something (or null
). Here, effectively you are asking React to render a promise
, hence your error.
You should extract this logic into the componentDidMount()
life cycle. Taking your code as an example, it could look something like this:
export class TrackCards extends ReactiveComponent {
constructor(props) {
super(['hash'])
this.state = {
kitties: []
}
}
async componentDidMount() {
const kitties = [];
var i = this.state.hash;
var root_hash = "0x11da6d1f761ddf9bdb4c9d6e5303ebd41f61858d0a5647a1a7bfe089bf921be9";
var root = "17,218,109,31,118,29,223,155,219,76,157,110,83,3,235,212,31,97,133,141,10,86,71,161,167,191,224,137,191,146,27,233";
var iter = 0;
var a;
while (root != i.toString()) {
var kitty = await runtime.template.kitties(i);
kitties.push(
<div className="column" key={i}>
<KittyShrieks
owner_count = {runtime.template.kittyHistoryCount(i)}
hash_original = {this.state.hash}
/>
</div>
);
i = kitty.parent_hash;
}
this.setState(
kitties
);
}
render () {
const { kitties } = this.state;
return (
kitties.length
? <div className="ui stackable six column grid">{kitties}</div>
: <span>Nothing to track</span>
)
}
}
We are initially returning <span>Nothing to track</span>
, while you are waiting for kitties
to complete.