The sub component below is supposed to display navigation buttons and render the appropriate result on button press (first, next, prev, last). Unfortunately, due to the asynchronous nature of inputs (fast button presses), I can not capture all button presses to process in order. I modified the sub component to be as simple as possible, but unfortunately it does not even respond to button presses, because I am not sure how to handle changes to the property, namely this.requests?
How do I make this work according to the intended behavior?
Sub Component
import React from 'react';
export class EditRiskNavigationButtons extends React.Component {
constructor(props){
super(props)
this.state = {
riskid : props.riskId
}
this.requests = []
}
queueRequest = (request) => {
this.requests.push(request);
}
handleNextRequest = () => {
if (this.requests.length) {
return this.props.getRisk(this.requests.shift());
}
}
render() {
return (
<div>
<input type="button" value="First" onClick={this.queueRequest.bind(this, 'first')} />
<input type="button" value="Prev" onClick={this.queueRequest.bind(this, 'prev')} />
<input type="button" value="Next" onClick={this.queueRequest.bind(this, 'next')} />
<input type="button" value="Last" onClick={this.queueRequest.bind(this, 'last')} />
</div>
);
}
}
Main Component
import React from 'react';
import { render } from 'react-dom/cjs/react-dom.development';
import { ThemeProvider } from 'styled-jss';
import { formatDateMDY } from '../../common/Functions';
import { EditRiskNavigationButtons } from './EditRiskNavigationButtons';
//import './EditRisk.jss';
class EditRisk extends React.Component {
constructor(props) {
super(props)
this.formatDateMDY = formatDateMDY.bind(this);
this.getRisk = this.getRisk.bind(this);
this.state = {
error: null,
isLoaded: false,
risk: [],
riskid: 0,
riskAPIUriParams: '',
message: ''
};
}
getRisk = (gotoRisk = 'first') => {
this.state.riskAPIUriParams = (this.state.riskid || "") + "/" + gotoRisk
if (this.state.riskid != 0)
this.state.riskAPIUriParams = "/" + this.state.riskAPIUriParams;
return fetch("http://projectaim/api/risks"+this.state.riskAPIUriParams)
.then(res => res.json())
.then(
(result) => {
this.setState({
isLoaded: true,
risk: result.data,
riskid: result.data.riskid,
message: result.message
});
},
// Note: it's important to handle errors here
// instead of a catch() block so that we don't swallow
// exceptions from actual bugs in components.
(error) => {
this.setState({
isLoaded: true,
error
});
}
)
}
componentDidMount() {
if (!this.state.isLoaded)
this.getRisk('first');
}
handleSubmit(event){
}
render() {
const { error, isLoaded } = this.state;
if (error) {
return <div>Error: {error.message}</div>;
} else if (!isLoaded) {
return <div>Loading...</div>;
} else {
return (
<div id="formcontainer">
<div id="myeditform">
<form id="form" name="EditRisk" ng-submit="">
<div class="layout"></div>
<EditRiskNavigationButtons getRisk={this.getRisk} />
{JSON.stringify(this.state.risk.riskid)}
</form>
</div>
</div>
);
}
}
}
render(<EditRisk/>, document.getElementById("root"))
Unclear if this is a definitive solution, but I believe using async / await in a polling loop code captures all requests. Any comments or revisions are appreciated.
import React from 'react';
export class EditRiskNavigationButtons extends React.Component {
constructor(props){
super(props)
this.state = {
riskid : props.riskId
}
this.requests = []
}
queueRequest = (request) => {
this.requests.push(request);
}
processNextRequest = async () => {
var nextRequest;
if (this.requests.length) {
nextRequest = this.requests.shift();
}
return this.props.getRisk(nextRequest);
}
pollForRequests = async () => {
while (true) {
await this.processNextRequest();
}
}
componentDidMount() {
this.pollForRequests();
}
render() {
return (
<div>
<input type="button" value="First" onClick={this.queueRequest.bind(this, 'first')} />
<input type="button" value="Prev" onClick={this.queueRequest.bind(this, 'prev')} />
<input type="button" value="Next" onClick={this.queueRequest.bind(this, 'next')} />
<input type="button" value="Last" onClick={this.queueRequest.bind(this, 'last')} />
</div>
);
}
}
I also need to modify processNextRequest like below to return a promise that waits for this.requests[] to get at least one element on it to prevent unnecessary looping unless the user clicks one or more times on the navigation button.
processNextRequest = async () => {
var nextRequest;
if (this.requests.length) {
nextRequest = this.requests.shift();
return this.props.getRisk(nextRequest);
}
else
{
return new Promise((resolve, reject) => {
setTimeout(() => resolve(this.requests.length));
});
}
}