Reputation: 59
I want to use the result of a server method that does a count on a collection to show it in the render method of a react component. I understand that I must do it from the callback function but it doesn't work for me.
Server Method:
export const analysis = new ValidatedMethod({
name: "analysis",
validate: new SimpleSchema({
codigo: {
type: String
},
rta: {
type: String
}
}).validator(),
run(one) {
const rta = Respuesta.find({
codigo: one.codigo,
rtatexto: one.rta,
activo: true
}).count();
console.log(rta);
return Number(rta);
}
});
Call from client:
export default class AnalysisFila extends Component {
constructor(props) {
super(props);
}
render() {
const one = { codigo: this.props.codigo, rta: this.props.opcion };
const rta = analysis.call(one, (err, res) => {
return (
<Table.Row>
<Table.Cell> {this.props.opcion} </Table.Cell>
<Table.Cell> {res} </Table.Cell>
</Table.Row>
);
});
}
}
How do I use the value of res in my component's render method?
Upvotes: -1
Views: 5659
Reputation: 4802
Before I answer the question, it is important to understand the difference between synchronous and asynchronous functions in JavaScript.
Therefore, if you are new to JavaScript or asynchronous behaviours, I recommend you read up on this excellent answer and explanation about the topic
The problem here is that React's render()
method is a synchronous method, meaning React expects a synchronous return value with jsx
(or a React.Element
for that matter).
For React, your current render function actually returns nothing or undefined
, as you do not a have a synchronous return
statement. And so nothing will get rendered.
React has no way of knowing when your callback is called or what it returns, as it is executed completely out of Reacts context.
The way to go here is to use Reacts state which is exactly for these kind of scenarios.
By using state and the method setState()
, you can asynchrounously trigger the render-method to be called again as soon as the response from your API delivered the data. Also, with this.state
, you can bring the response-data into the react-context and let it know about it.
A full example could look like this:
export default class AnalysisFila extends Component {
constructor(props) {
super(props);
this.state = {
loaded: false
opcion: {}
};
}
componentDidMount() {
const one = { codigo: this.props.codigo, rta: this.props.opcion };
const rta = analysis.call(one, (err, res) => {
this.setState({
loaded: true,
opcion: res
}
});
}
render() {
const content = this.state.loaded ? this.state.opcion : 'Loading...';
return (
<Table.Row>
<Table.Cell> {this.props.opcion} </Table.Cell>
<Table.Cell> {content} </Table.Cell>
</Table.Row>
);
}
}
I also used the componentDidMount
-Lifecycle-Method of React, as it is the recommended way to trigger API Calls. You can read more about Lifecycles in the official lifecycle documentation
The Life-Cycle of this Component will be like the following:
this.state
render()
method is called with this.state.loading === false
- thus the content will default to the string 'loading...'componentDidMount()
function gets called and will trigger your API-CallsetState()
, putting the response-data into this.state
render()
method again. But this time, this.state.loading === true
and there is some value for this.state.opcion
- thus the content will be the value from your response.Upvotes: 1