React twilio.Js Library Accept Incoming Call - javascript

I am trying to accept incoming calls with the twilio.Js Library. (https://www.twilio.com/docs/api/client)
I am listening for the incoming calls like this:
componentDidMount() {
Twilio.Device.incoming((conn) => {
console.log('Incoming connection from ' + conn.parameters.From);
});
}
I know that I can just call conn.accept(); in the Twilio.Device.incoming function, however for my component to work, I would need to be able to accept the call outside of the componentDidMount() function.
So preferably I would have a function like this:
acceptCall() {
// Do something to accept call
}
Is there any expert here, that could quickly help me?

Ok I figured it out myself.
What I need to do is the following:
constructor(props){
super(props);
this.state = {
inboundConn: null
};
}
// Initialize after component creation
componentDidMount() {
Twilio.Device.incoming((conn) => {
this.setState({
inboundConn: conn
});
});
}
acceptCall() {
this.state.inboundConn.accept();
}

Related

Value is not assigning inside then statement

In this js file I have defined this const Device that is the name of the mobile im using. The thing is when I call Device from another js it returns it empty. Why?
import DeviceInfo from 'react-native-device-info';
var Device = ''
DeviceInfo.getDeviceName().then(deviceName => {
Device = deviceName + ' ('+DeviceInfo.getSystemVersion()+')'
});
export default Device;
The reason why your current approach doesn't work is because DeviceInfo.getDeviceName is an asynchronous call that returns a Promise which resolves with the deviceName.
var Device = ''
DeviceInfo.getDeviceName().then(...)
// the call above will not wait before it goes to next line
// so `Device` will stay as empty string and will be exported as such
export default Device
Instead, if you want to re-use this logic in multiple places, I suggest turning this into a function, like in the following example:
import DeviceInfo from 'react-native-device-info';
function getDeviceFullName() {
return DeviceInfo.getDeviceName()
.then(deviceName => {
return `${deviceName} (${DeviceInfo.getSystemVersion()})`
})
}
export default getDeviceFullName
Then, somewhere else, you could call this function like in the following example:
import getDeviceFullName from './getDeviceFullName'
class App extends React.Component {
state = {deviceName: ""}
componentDidMount() {
getDeviceFullName()
.then(deviceName => {
this.setState({ deviceName })
})
.catch(/* handle errors appropriately */)
}
render() {
return this.state.deviceName === ""
? "Loading"
: this.state.deviceName;
}
}
EDIT as OP mentioned something about Formik integration.
Haven't tested this, but something like the following would be my approach.
class MyReactNativeForm extends React.Component {
state = {
initialValues: { email: "johndoe#gmail.com", deviceName: "" }
}
componentDidMount() {
getDeviceFullName()
.then(deviceName => {
this.setState(prevState => {
return {
initialValues: {...prevState.initialValues, deviceName}
}
})
})
.catch(/* handle errors appropriately*/)
}
render() {
return this.state.initialValues.deviceName === ""
? "Loading"
: <Formik initialValues={this.state.initialValues} />
}
Edit: Someone else posted a great answer while I was typing mine up. My answer re-uses the value for Device because that is how the original question worked. Like the approved answer, you don't need to set it and forget it, but instead you can only return a cb/promise that always gets the most recent data.
Two things immediately stand out. Like #mhodges says, you can't reassign a value to a constant. Instead, you should use let.
Your next issue is trying to export the value returned by an asynchronous call. When you import Device from your js file, the export statement executes before you re-assign the value of Device.
What if you exported your async function or a callback instead?
Promise'able:
var Device;
export function getDeviceInfo() {
if (Device) return Promise.resolve(Device);
return DeviceInfo.getDeviceName().then(deviceName => {
Device = deviceName + ' ('+DeviceInfo.getSystemVersion()+')';
return Promise.resolve(Device);
});
}
Usage might look like:
import { getDeviceInfo } from './utils';
getDeviceInfo().then((deviceInfo) => console.log('Got it!', deviceInfo));
Callback'able:
var Device;
export function getDeviceInfo(cb) {
if (Device) return cb(Device);
DeviceInfo.getDeviceName().then(deviceName => {
Device = deviceName + ' ('+DeviceInfo.getSystemVersion()+')';
cb(Device);
});
}
Usage might look like:
import { getDeviceInfo } from './utils';
getDeviceInfo(function(deviceInfo) {
console.log('Got it!', deviceInfo)
});

JS React: error of this.x is not a function, even when this.x function is bound

I'm trying to update to update the window state whenever the App component mounts. With the below code, I receive an Error in response to tabs.query: TypeError: this.addTabs is not a function.
I don't understand why this.addTabs is not considered a function, as the function is above the reference to this.addTabs(tabs), and I think it was correctly bound.
class App extends Component {
constructor(props){
super(props);
this.state = {
window: []
};
this.addTabs = this.addTabs.bind(this);
}
addTabs(tabs){
this.setState({window:this.state.window.concat(tabs)});
};
componentDidMount(){
chrome.tabs.query({active:true},function(tabs){
this.addTabs(tabs);
});
I'm not looking to use the arrow function. I looked at similar questions, and the response was to bind the function in the constructor, which I believe I did. Any help or pointers would be appreciated!
Your issue is in this block:
componentDidMount(){
chrome.tabs.query({active:true},function(tabs){
this.addTabs(tabs);
});
}
Inside your callback, the context is different so this refers to another context.
You have several ways to fix it.
1) Assign the ref to this outside the callback and use that ref:
componentDidMount(){
const that = this;
chrome.tabs.query({active:true},function(tabs){
that.addTabs(tabs);
});
}
2) Bind the current this to the callback:
componentDidMount(){
chrome.tabs.query({active:true},(function(tabs){
this.addTabs(tabs);
}).bind(this));
}
3) Use an arrow function:
componentDidMount(){
chrome.tabs.query({active:true}, (tabs) => {
this.addTabs(tabs);
});
}

react setState doesnt work neither its callback

when i call this.setState in my code it seems to do nothing at all
this.setState({array:pre.array},()=>{console.log("setState")})
i can't even see the log from the call back function here is my code
class Watch extends React.Component{
constructor(pre) {
super(pre);
this.state = { color: "green" }
this.setState(() => {
return {array:newarray}
}, console.log("setState works"))
p.s:i have tried to put setState in onClick function, in componentDidMount(),componentDidUpdate() still dosent work with no error
It seems like when using setState callback system, the first parameter (updater) needed to be in the form of a function as well. So you can try something like:
onEditText=(value)=>{
this.setState((state, props)=>{
return {text: value}
}, this.onTextEdited);
}
onTextEdited=()=>{
//this will be printed with the updated value
console.log('onTextEdited', this.state.text)
}
See if this helps.

Using Map in React with firebase

Someone please help. I have combed all of the doc's, examined all similar questions and really cannot see what I am missing.
I am new to react and trying to map over documents returned from an asynchronous call from a firebase db.
Here is the code:
class Posts extends React.Component {
constructor(props) {
super(props);
this.state = {
data: [],
};
}
componentDidMount() {
let posts = [];
db.collection("Posts").get().then(function(querySnapshot) {
querySnapshot.forEach(function(doc) {
posts.push({
data: doc.data(),
id: doc.id
});
});
});
this.setState({
data: posts
});
}
renderPosts() {
console.log(this.state.data);
return this.state.data.map((post, index) => {
console.log(post);
console.log(index);
return (
<div>
{index}
</div>
)
})
}
render() {
return(
<div>
{this.renderPosts()}
</div>
);
}
}
I am sure it is something super simple but I am pulling my hair out. If I examine my state I can see the data. console.log(this.state.data); inside renderPosts even displays exactly what I need to map over, but everything inside the map callback doesn't return and I end up with a single empty Any help would be greatly appreciated.
As Li357 commented, the setState call needs to happen inside the get() callback:
db.collection("Posts").get().then(function(querySnapshot) {
querySnapshot.forEach(function(doc) {
posts.push({
data: doc.data(),
id: doc.id
});
});
this.setState({
data: posts
});
});
The reason for this is that data is loaded from Firestore asynchronously, and by the time you were calling setState the posts variable was still empty.
The easiest way to understand this type of asynchronous loading is with a few log lines:
console.log("Before starting to get documents");
db.collection("Posts").get().then(function(querySnapshot) {
console.log("Got documents");
});
console.log("After starting to get documents");
When you run this, the output is:
Before starting to get documents
After starting to get documents
Got documents
That is probably not the order you expected the output in. But it is the expected behavior: instead of blocking the code while the data is loaded (which would freeze the browser), the code after the get().then() block immediately executes. And then when the data is loaded, the code in the then callback is executed. That's why all code that needs the documents from the database needs to be inside the then callback.

Consuming REST resources before rendering in React.js

I have React components that consumes external webservice to reach data for rendering.
I would like the data being loaded BEFORE the rendering because I want it to be indexed by search engines.
Here is my component :
class AboutPage extends React.Component {
async componentWillMount() {
let response = await EventWS.doSearch();
this.setState({
eventList : response.data
})
}
render() {
/* ... */
}
}
(I tried to use async/await because I thought it could help, but no).
When trying to load the page with server side rendering I got the warning :
Warning: setState(...): Can only update a mounting component. This usually means you called setState() outside componentWillMount() on the server. This is a no-op. Please check the code for the FluxContainer(AboutPage) component.
Indicating that the setState is done AFTER the componentWillMount has ended.
In my specific case, what is best way to acheving this ? Is there a easy way to do an ajax call synchronously ? Is it recommended to do so ?
Thank you.
EDIT :
I have found a library that allow to make synchronous call :
https://github.com/ForbesLindesay/sync-request
But it states that it is not well suited for production. So I'am a bit disapointed.
I dont have a lot of experience with Flux but it seems like you should do this in the componentDidMount method.
You can use Axios promise based get in componentDidMount to implement it, for an example you can refer Handling Events In React and below sample code:
constructor(props) {
super(props);
this.state = {eventList: []};
this.Axios = axios.create();
}
componentDidMount() {
let _this = this;
this.Axios.get('/your/rest/url')
.then(function (response) {
console.log(response);
_this.setState({eventList: response.data});
}).catch(function (error) {
console.log(error);
});
}
Or if you are already using Axios then make sure EventWS.doSearch() return Promise to you and call it in componentDidMount, as follows:
constructor(props) {
super(props);
this.state = {eventList: []};
}
componentDidMount() {
let _this = this;
EventWS.doSearch().then(function (response) {
console.log(response);
_this.setState({eventList: response.data});
}).catch(function (error) {
console.log(error);
});
}

Categories

Resources