Reputation: 31237
I'm trying to implement Bullet train API in a React web app. According to their node client documentation, I have setup the following function:
export const isFeatureEnabled = async (nameOfTheFeature) => {
return new Promise((resolve) => {
bulletTrain.init({
environmentID: BULLET_TRAIN_ENV_ID
});
bulletTrain.hasFeature(nameOfTheFeature)
.then((featureFlag) => {
if (featureFlag[nameOfTheFeature].enabled) {
resolve(true);
}
})
.catch(err => resolve(false));
});
}
This is called in regular components like this:
render() {
return (<div>{await isFeatureEnabled('feature1') && <p>feature1 is enabled</p>}</div>)
};
which throws this:
Parsing error: Can not use keyword 'await' outside an async function
If we add the async keyword, with a proper return statement:
async render() {
return (<div>{await isFeatureEnabled('feature1') && <p>feature1 is enabled</p>}</div>)
};
Then it throws:
Your render method should have return statement
So what is the correct way to use this promised function inside a react app?
Upvotes: 1
Views: 94
Reputation: 348
You can't use promise at there, the proper way:
import React, { useEffect, useState } from 'react'
import bulletTrain from '../somewhere'
import BULLET_TRAIN_ENV_ID from '../somewhere'
export default function featureComponent({ featureName }) {
const [featureEnabled, setFeatureEnabled] = useState(false)
useEffect(() => {
bulletTrain.init({
environmentID: BULLET_TRAIN_ENV_ID
})
bulletTrain
.hasFeature(featureName)
.then(featureFlag => {
if (featureFlag[featureName].enabled) {
setFeatureEnabled(true)
}
})
.catch(err => setFeatureEnabled(false))
}, [featureName])
return <div>{featureEnabled && <p>{featureName} is enabled</p>}</div>
}
Append isFeatureEnabled
function re-use answer below:
import React, { useEffect, useState } from 'react'
import isFeatureEnabled from '../somewhere'
export default function featureComponent({ featureName }) {
const [featureEnabled, setFeatureEnabled] = useState(false)
useEffect(() => {
const checkAndSetEnabled = async () => {
const enabled = await isFeatureEnabled(featureName)
setFeatureEnabled(enabled)
}
checkAndSetEnabled()
}, [featureName])
return <div>{featureEnabled && <p>{featureName} is enabled</p>}</div>
}
Upvotes: 1
Reputation: 74738
I would suggest you not to use await
keyword in render
instead use componentDidMount
and constructor
for this and use state object to check:
constructor(props){
super(props);
this.state = { isFeatEnabled: false };
}
componentDidMount(){
this.setState({isFeatEnabled:isFeatureEnabled('feature1')})
}
Now in the render:
render() {
return (<div>{this.state.isFeatEnabled && <p>feature1 is enabled</p>}</div>)
};
And remove the async
from the method.
Upvotes: 1
Reputation: 325
call function isFeatureEnabled inside an async function during mount (before/after your wish)
example -
export const isFeatureEnabled = async (nameOfTheFeature) => {
return new Promise((resolve) => {
bulletTrain.init({
environmentID: BULLET_TRAIN_ENV_ID
});
bulletTrain.hasFeature(nameOfTheFeature)
.then((featureFlag) => {
if (featureFlag[nameOfTheFeature].enabled) {
resolve(true);
}
})
.catch(err => resolve(false));
});
}
...
componentDidMount() {
this.checEnabled();
}
...
const checkEnabled = async () => {
const flag = await isFeatureEnabled('feature1');
this.setState({f1enabled: flag});
}
...
render() {
return (<div>{this.state.f1enabled ? <p>feature1 is enabled</p> : null}</div>)
}
If isFeatureEnabled is in the same file keep it outside class component or else keep it in another file and export the function.
Upvotes: 1