I'm facing with problem,
I'm use context for socket io.
In App.js:
let loginInfo;
let socket = null;
// Listening notification on background or quit
messaging().setBackgroundMessageHandler(async remoteMessage => {
// Init socket,
// Start call
});
// Read AsyncStorage
const getLoginData = async () => {
loginInfo = JSON.parse(await AsyncStorage._retrieveData('loginInfo'));
if (loginInfo && loginInfo?.isJoinedRoom) {
socket = io(loginInfo.url, {timeout: 10000, reconnection: false});
// Here print later
console.log('socket in appjs: ', socket); // 1 -> Socket in here assigned
}
};
getLoginData();
const App = () => {
// here print first
console.log('Socket in appjs 2', socket); // 2 -> Socket in here is null
return (
<>
<SocketProvider value={socket}>
<MainContainer />
</SocketProvider>
</>
);
};
export default App;
I'm want to wait function getLoginData is completed before rendering App. SocketProvider with value alway null.
Can you show me how to wait a function completed before rendering, thank.
I try to set another variable in getLoginData let completed = false
and use in App.js but not work :
{completed ? (
<SocketProvider value={socket}>
<MainContainer />
</SocketProvider>
) : (
<></>
)}
The completed won't work because you are using completed = false in getLoginData as a normal variable... You'll have to use it as a state, i.e.
const [completed, setCompleted] = useState(false);
And then in the getLoginData function, once you are done, set the state to true
And use it just like you used it above.
Related
I am using RNCallkeep to handle call inside my App.
In case app active or in background, when user answer call, I using this code to navigate into Call Screen:
App.js file
RNCallKeep.addEventListener('answerCall', answerCall)
const answerCall = ({callUUID}) => {
console.log(`[answerCall] ${callUUID}`)
RNCallKeep.setCurrentCallActive(callUUID)
const callData = CallManager.getInstance().getAllCall().find(c => c.callId.toString().toUpperCase() === callUUID.toString().toUpperCase())
if(callData){
const masterInfo = JSON.parse(storage.getString(STORAGE_PARAMS.MASTER_INFO))
const data = callData.data
const mediaServers = JSON.parse(data.mediaServerAddress ?? data.MediaServerAddress)
const iceServsers = JSON.parse(data.iceServers ?? data.IceServers)
const roomJanusInfo = data
const room = { RoomId: data.roomId ?? data.RoomId, ServiceId: data.roomServerId ?? data.RoomServerId, RoomName: data.callerDisplay ?? data.CallerDisplay }
const isVideo = data.video ?? data.Video === 'True'
const isAudio = true
const isOutgoing = false
const callUser = { Id: data.callerId ?? data.CallerId, ServiceId: data.callerServiceId ?? data.CallerServiceId, Name: data.callerDisplay ?? data.CallerDisplay }
const roomAddress = mediaServers[0]
const videoRoomId = data.videoRoomId ?? data.VideoRoomId
const videoRoomPwd = data.videoRoomPwd ?? data.VideoRoomPwd
const audioRoomId = data.audioRoomId ?? data.AudioRoomId
const audioRoomPwd = data.audioRoomPwd ?? data.AudioRoomPwd
const roomController = RoomCallService
const url = `${baseurl(room.ServiceId, masterInfo)}${roomController.Controller}/${roomController.ContactCallUpdateSubStatus}`
const params = {
RoomId: room.RoomId,
CallId: data.callId ?? data.CallId,
SubStatus: VxLinkCallSubStatus.Accepted,
ClientType: ClientType.MobileApp
}
postData(url, params, '_ContactCallUpdateSubStatus')
.then(result => {
console.log('_ContactCallUpdateSubStatus success', result)
navigate('SingleCall', {
room: room,
callUUID: callUUID,
isVideo: isVideo,
isAudio: isAudio,
isOutgoing: isOutgoing,
callUser: callUser,
roomAddress: roomAddress,
videoRoomId: parseInt(`${videoRoomId}`),
videoRoomPwd: videoRoomPwd,
audioRoomId: parseInt(`${audioRoomId}`),
audioRoomPwd: audioRoomPwd,
iceServers: iceServsers,
roomJanusInfo: roomJanusInfo //for other purposes
})
}).catch(error => {
alert(error)
console.log('_ContactCallUpdateSubStatus error', error, url, params)
})
}
}
It's work fine, but in case app killed. I can not navigate into SingleCall screen, and I can not debug anything after force kill app
Can anyone help?
You have to wake up your application.
Receiving a call when the application is not reachable.
In some case your application can be unreachable :
when the user kill the application when it's in background since a long time (eg: after ~5mn the os will kill all connections). To be able to wake up your application to display the incoming call, you can use https://github.com/react-native-webrtc/react-native-voip-push-notification on iOS or BackgroundMessaging from react-native-firebase-(Optional)(Android-only)-Listen-for-FCM-messages-in-the-background).
You have to send a push to your application, like with Firebase for Android and with a library supporting PushKit pushes for iOS.
https://github.com/react-native-webrtc/react-native-callkeep#receiving-a-call-when-the-application-is-not-reachable
I am using react native, and axios.
I have two parts.
The exercice list that is rendered with useEffect in a div. Inside, there is a Input form which once pressed the Add set button, the set is added to the database and the exercices are fetched again with the passed function.
The main problem is that when I first add an exercice, the exercice s not rendering. I must go back and come again in the page to render the first one. after doing this process I can add as many exercices... And with delete is same. I can delete any exercice but when deleting the last one, it persist and I must leave the page to see the changes...
THIS IS THE FUNCTION THAT ADD THE exercices. It executes once the alert button is pressed
const NewExercice = ({dayID, getAllEx}) => {
// States and ontext change functions
const [exName, setexName] = useState('');
const [comment, setcomment] = useState('');
const handleExname = text => setexName(text);
const handleComments = text => setcomment(text);
// Add new exercices
const handleNewExercice = async () => {
try
{
const status = await data.post('/api/create-exercice', {dayID, exName, comments: comment});
Alert.alert(
'Exercice created',
'Please add new sets to existing exercices',
[
{
text: 'Ok!',
// Fetch again for all the exercices
onPress: getAllEx
}
]
)
}
catch (error)
{
console.log(error);
}
}
Bellow is the component that adds map over the array state
<View>
{error ? (<Text>No exercices created yet.</Text>) :
exArray.map(obj => (
<ExerciceWrapper getAllEx={getAllExercices} navigation={navigation} key={obj.exID} object={obj} />
))}
</View>
Bellow is the function that fetch the data from the DB and set the state to be able to be rendered in the component above
const getAllExercices = async () => {
try
{
const response = await data.get('/api/get-all-ex/' + dayID);
setExArray(response.data);
}
catch (error)
{
if (error.response.status === 404) return setError(true);
else return console.log(error);
}
}
useEffect(() => {
getAllExercices();
}, []);
You need to toggle the error value when you have successful fetch as well
update code to this
const getAllExercices = async () => {
try
{
const response = await data.get('/api/get-all-ex/' + dayID);
setExArray(response.data);
setError(response.data.length < 1)
}
catch (error)
{
if (error.response.status === 404) return setError(true);
else return console.log(error);
}
}
What I am trying to do is sync a list of attendees from an online database, and if the current user is in the list, then disable a button, else enable the button.
I am using react native hook (I am not sure if I am using the term correctly as I am fairly new to react), in order to set the value of disabling the button.
The issue that I am facing is that the value is getting initialized to false, even tho it should clearly get initialized to true.
After adding some logging I made sure that the function is executing correctly and reaching the code where it sets the value to true.
const [buttonDisabled, changeButtonState] = useState( () => {
var database = firebase.database();
var userId = firebase.auth().currentUser.uid;
const dbRef = firebase.database().ref();
var Attendees = [];
var disable = false;
dbRef.child("gameAttendees").child(gameinfo.gameID).get().then((snapshot) => {
if (snapshot.exists()) {
Attendees = snapshot.val().Attendees;
for(var i=0;i<Attendees.length;i++){
if(Attendees[i]==userId){
return true;
}
}
} else {
console.log("no value");
return false;
}
}).catch((error) => {
console.error(error);
});
});
Adding an example of an async mount effect:
const Comp = () => {
const [s, setS] = useState(); // State will be undefined for first n renders
useEffect(() => {
// Call the async function and set the component state some time in the future
someAsyncFunction().then(result => setS(result));
}, []); // An effect with no dependencies will run only once on mount
return </>;
};
This may be a basic question, but I'm new to React Native and stuck here.
My code pasted below. reducer and functional component. I want to capture the response returned from reducer.
reducer.js
export const ActivationCenterReducer = (
state = INIT_KIT_STATE,
{ type, payload = {} }
) => {
switch (type) {
case 'KIT_ACTIVATION_SUCCESS_DATA': {
const { message, response_code, apiLoading, apiError } = payload;
return {
...state,
apiLoading: apiLoading,
apiError: apiError,
message: message,
response_code: response_code
};
}
// ...
}
// ...
};
Functional Component class:
const kitActivationCenter = ({ route, navigation }) => {
const response_code = useSelector(
store => store.kitActivationCenter.response_code
);
const handleKitActivation = () => {
/*This will call the validation() inside action.js and that follows the reducer.js file. where reducer.js file returning the values on success response. but I am not able to access that response_code returned from reducer.
How to save the response_code from the below dispatch function.*/
dispatch(Validation(locator, pin));
if (response_code === 200) {
// should navigate to the next screen
}
};
};
My question is how to capture the returned response_code from reducer.
I'm able to navigate to the next screen on clicking the submit button couple of times.I notice that first time when the dispatch function is called, the state of the response_code is not updating , hence the response_code != 200.
I want a way to capture the response and assign to variable.
Thanks in advance.
You are probably looking at the old value of response_code in your handleKitActivation.
const kitActivationCenter = ({ route, navigation }) => {
const response_code = useSelector(
store => store.kitActivationCenter.response_code
);
const handleKitActivation = () => {
dispatch(Validation(locator, pin));
// HERE the response_code does not have result value
// of your calling dispatch(Validation(locator, pin)) above yet
if (response_code === 200) {
// should navigate to the next screen
}
};
};
I suggest to move your response_code hanfling to the useEffect:
const kitActivationCenter = ({ route, navigation }) => {
const response_code = useSelector(
store => store.kitActivationCenter.response_code
);
// this effect will run whenever your response_code changes
useEffect(() => {
if (response_code === 200) {
// should navigate to the next screen
}
}, [response_code]);
const handleKitActivation = () => {
dispatch(Validation(locator, pin));
};
};
Can react-native-testing-library find an alert, created with Alert.alert()?
My app creates the alert as expected but this test is failing:
// test
const Wrapper = props => (
<Fragment>
<SubscriptionProductDetailScreen
product={product}
testID={"SUBSCRIPTION_DETAIL_SCREEN"}
addToCart={addToCartSpy}
{...props}
/>
</Fragment>
);
function createWrapper(customProps) {
const wrapper = render(<Wrapper {...customProps} />);
return wrapper;
}
beforeEach(() => {
wrapper = createWrapper();
});
// later, inside a describe block:
it('should show an alert if no bars are selected', async () => {
pressSubmitButton()
expect(addToCartSpy).not.toHaveBeenCalled()
// const alert = await waitForElement(
// wrapper.queryByText("Please select up to 4 free items.")
// )
const alert = wrapper.queryByText("Please select up to 4 free items.")
expect(alert).not.toBeNull()
});
// brief excerpt from the component (the onPress handler for the submit button)
addToCart() {
const freeItems = this.state.items[0]
if (!freeItems || !freeItems.selections.length) {
Alert.alert("Error", "Please select up to 4 free items.")
return
}
const item: {...}
this.props.addToCart(item)
}
The async version (waitForElement, commented) also fails.
Again, the alert works in the app itself, and the assertion that the dispatch action, called by the handler, passes.
Alert is not within a React application stack - it's a system feature, so it can't be directly tested with react-native-testing-library. You can however at least verify if it was executed:
import { Alert } from 'react-native'
jest.mock('react-native', () => {
const RN = jest.requireActual('react-native')
return Object.setPrototypeOf(
{
Alert: {
...RN.Alert,
alert: jest.fn(),
},
},
RN,
)
})
test('...', () => {
// ...
expect(Alert.alert).toHaveBeenCalled()
})