I am trying to run a background task using headlessjs in react-native. The problem is that I am unable to access the async task inside the component in order to show it on the view. Here's my default component.
import React, { Component } from 'react';
import {
AppRegistry,
Text,
View,
NativeModules
} from 'react-native';
module.exports = NativeModules.ToastAndroid;
someTask = require('./SomeTaskName.js');
export default class test2 extends Component {
constructor() {
super()
this.state = {
myText: 'My Original Text'
}
}
updateText = () => {
this.setState({myText: 'My Changed Text'});s
}
componentDidMount(){
this.setState({myText: someTask});
someTask.then(function(e){ //<--- error
console.log("lala" + e);
});
}
render() {
return (
<View>
<Text>
abc
</Text>
</View>
);
}
}
AppRegistry.registerComponent('test2', () => test2);
AppRegistry.registerHeadlessTask('SomeTaskName', () => someTask);
As mentioned in the code, I get the error undefined is not a function. I don't know how to make this work. My SomeTaskName.js looks like this.
SomeTaskName.js
module.exports = async (taskData) => {
return taskData.myname;
}
The idea is to simply get the data from the service and show it on the UI.
The solution was to simply move the code inside the componentDidMount function. Here's how I achieved it.
/**
* Sample React Native App
* https://github.com/facebook/react-native
* #flow
*/
import React, { Component } from 'react';
import {
AppRegistry,
Text,
View,
Image
} from 'react-native';
export default class test2 extends Component {
constructor() {
super()
this.state = {
myText: '1'
}
}
componentWillUnmount() {
}
componentDidMount(){
someTask = async (taskData) => {
this.setState({ myText: taskData.myname});
}
};
}
render() {
return (<Text>Working</Text>);
}
}
AppRegistry.registerHeadlessTask('SomeTaskName', () => someTask);
AppRegistry.registerComponent('test2', () => test2);
You can replace :
someTask = require('./SomeTaskName.js');
by
import SomeTaskName from './SomeTaskName'
Related
I am very new to react native. The app I am developing has functional components.
Is there any way to convert class component to function component or convert this class into a function?
Is it possible to use functional and class component both in single app?
import React from 'react';
import DayPicker, { DateUtils } from 'react-day-picker';
import 'react-day-picker/lib/style.css';
export default class Example extends React.Component {
constructor(props) {
super(props);
this.handleDayClick = this.handleDayClick.bind(this);
this.state = {
selectedDays: [],
};
}
handleDayClick(day, { selected }) {
const { selectedDays } = this.state;
if (selected) {
const selectedIndex = selectedDays.findIndex(selectedDay =>
DateUtils.isSameDay(selectedDay, day)
);
selectedDays.splice(selectedIndex, 1);
} else {
selectedDays.push(day);
}
this.setState({ selectedDays });
}
render() {
return (
<div>
<DayPicker
selectedDays={this.state.selectedDays}
onDayClick={this.handleDayClick}
/>
</div>
);
}
}
Yes you can use both functional and class component in same time
import React, {useState} from "react";
import DayPicker, { DateUtils } from 'react-day-picker';
import 'react-day-picker/lib/style.css';
export default function Example(props = {}) {
// read about useState hooks, it replace state
const [selectedDays, setSelectedDays] = useState([]);
handleDayClick(day, { selected }) {
if (selected) {
const selectedIndex = selectedDays.findIndex(selectedDay =>
DateUtils.isSameDay(selectedDay, day)
);
selectedDays.splice(selectedIndex, 1);
} else {
selectedDays.push(day);
}
setSelectedDays( selectedDays );
}
render() {
return (
<div>
<DayPicker
selectedDays={ selectedDays}
onDayClick={handleDayClick}
/>
</div>
);
}
}
The function componentDidMount is not firing.
This is some of my code:
import React, { Component } from 'react';
import { Block } from 'galio-framework';
export function FriendRequests ( ) {
const username = 'abcd';
componentDidMount = () => {
alert("abcd");
}
return (
line number 37: <Block>....</Block>
)
}
You are using the functional component which doesn't have the lifecycle methods.
Solution 1:
import React, { Component } from 'react';
import { View, Text } from 'react-native';
class FriendRequests extends Component {
constructor(props) {
super(props);
this.state = {
};
}
componentDidMount = () => {
alert("abcd");
}
render() {
return (
<View>
<Text> Your text Here </Text>
</View>
);
}
}
export default FriendRequests;
Solution 2:
If you want to use it as functional component then you can use the React Hook and can make use of useEffect() method from the hook instead of componentDidMount. method to handle after render stuff.
First of all,
export function FriendRequests ( ) {
componentDidMount = () => {
alert("abcd");
}
return (
....
)
}
this is a functional component, and functional component dont have any inbuilt functions like componentDidMount. Only class based components have access, So try this:
UPDATE:
export class FriendRequests extends React.Component {
componentDidMount() {
alert("abcd");
}
render() {
return (
<View>
<Text>hey</Text>
</View>
);
}
}
hope it helps. feel free for doubts
I installed the react-navigation package in react-native
I have implemented tab navigation and one of them is implemented in webview format.
My problem is that if I press the back physical button on Android, I go from the app itself to the previous tab, not back from the webview.
I've already applied the back button for the webview on the internet, but I have not done that.
I tried to display the onNavigationStateChange log when debugging, but it was not updated when url was moved after it was loaded at first startup. Here is the code I implemented:
import React from "react";
import {BackHandler} from "react-native";
import {WebView} from "react-native-webview";
class SermonScreen extends React.Component {
constructor(props) {
super(props);
}
static navigationOptions = {
header: null
};
componentDidMount() {
BackHandler.addEventListener('hardwareBackPress', this.handleBackButton);
}
componentWillUnmount() {
BackHandler.removeEventListener('hardwareBackPress', this.handleBackButton);
}
_onNavigationStateChange(navState) {
console.log(navState);
this.setState({
canGoBack: navState.canGoBack
});
}
handleBackButton = () => {
console.log(this.state);
if (this.state.canGoBack === true) {
this.webView.goBack();
return true;
} else {
return false;
}
};
render() {
return (
<WebView
source={{uri: 'https://m.youtube.com/channel/UCw3kP3qCCF7ZpLUNzm_Q9Xw/videos' }}
ref={(webView) => this.webView = webView}
onNavigationStateChange={this._onNavigationStateChange.bind(this)}
/>
);
}
}
export default SermonScreen;
Following the official webview documnentation you could try to do this: https://github.com/react-native-community/react-native-webview/blob/master/docs/Guide.md#intercepting-hash-url-changes
In general you were almost there, however the way the YT navigation works made it impossible to be caught via the onNavigationStateChange, that's why we inject a JS code that intercepts these hash changes and posts a message to the parent component, we then catch it inside the onMessage handler and set the state variable properly. Copying the injectedJavaScript and onMessage properties to your example should solve your problem.
I prepared a component for you that seems to do what is needed:
* Sample React Native App
* https://github.com/facebook/react-native
*
* #format
* #flow
*/
import React, { Fragment } from "react";
import {
SafeAreaView,
StyleSheet,
ScrollView,
View,
Text,
BackHandler,
StatusBar
} from "react-native";
import { WebView } from "react-native-webview";
import {
Header,
LearnMoreLinks,
Colors,
DebugInstructions,
ReloadInstructions
} from "react-native/Libraries/NewAppScreen";
class App extends React.Component {
constructor(props) {
super(props);
this.startingUrl =
"https://m.youtube.com/channel/UCw3kP3qCCF7ZpLUNzm_Q9Xw/videos";
this.handleBackButton = this.handleBackButton.bind(this);
}
componentDidMount() {
BackHandler.addEventListener("hardwareBackPress", this.handleBackButton);
}
componentWillUnmount() {
BackHandler.removeEventListener("hardwareBackPress", this.handleBackButton);
}
handleBackButton = () => {
console.log(this.state);
const { canGoBack } = this.state;
if (canGoBack) {
this.webView.goBack();
return true;
} else {
return false;
}
};
render() {
return (
<Fragment>
<WebView
source={{ uri: this.startingUrl }}
style={{ marginTop: 20 }}
ref={webView => (this.webView = webView)}
injectedJavaScript={`
(function() {
function wrap(fn) {
return function wrapper() {
var res = fn.apply(this, arguments);
window.ReactNativeWebView.postMessage('navigationStateChange');
return res;
}
}
history.pushState = wrap(history.pushState);
history.replaceState = wrap(history.replaceState);
window.addEventListener('popstate', function() {
window.ReactNativeWebView.postMessage('navigationStateChange');
});
})();
true;
`}
onMessage={({ nativeEvent: state }) => {
if (state.data === "navigationStateChange") {
// Navigation state updated, can check state.canGoBack, etc.
this.setState({
canGoBack: state.canGoBack
});
}
}}
/>
</Fragment>
);
}
}
export default App;
The response above was perfect. I set the state true for canGoBack though; I was getting a null error, so:
constructor(props) {
super(props);
this.startingUrl = "https://app.vethorcardpag.com.br/GIF/login/0/";
this.state = {
canGoBack : true
}
this.handleBackButton = this.handleBackButton.bind(this);
}
Here is a simple solution using the magic of React's State.
Hope this helps.
import React, { useRef, useState } from 'react'
export default function Component () {
// This is used to save the reference of your webview, so you can control it
const webViewRef = useRef(null);
// This state saves whether your WebView can go back
const [webViewcanGoBack, setWebViewcanGoBack] = useState(false);
const goBack = () => {
// Getting the webview reference
const webView = webViewRef.current
if (webViewcanGoBack)
// Do stuff here if your webview can go back
else
// Do stuff here if your webview can't go back
}
return (
<WebView
source={{ uri: `Your URL` }}
ref={webViewRef}
javaScriptEnabled={true}
onLoadProgress={({ nativeEvent }) => {
// This function is called everytime your web view loads a page
// and here we change the state of can go back
setWebViewcanGoBack(nativeEvent.canGoBack)
}}
/>
)
}
Original answer
https://stackoverflow.com/a/74500469/7823800
I am complete noob and am just following a tutorial in react-native on udemy. However, I have reached a wall and cannot find a solution anywhere?
Currently I am getting an error from ESLint showing that state is undefined.
Here is the complete code:
import React, { Component } from 'react';
import { View, Text } from 'react-native';
import axios from 'axios';
class AlbumList extends Component {
state = { albums: [] }; //state is underlined
ComponentWillMount() {
axios.get('https:/rallycoding.herokuapp.com/api/music_albums')
.then(response => this.setState({ albums: response.data }));
}
renderAlbums() {
render() {
console.log(this.state);
return (
<View>
{this.renderAlbums()}
</View>
**strong text**);
}
}
export default AlbumList;
Has there been any update regarding defining 'state' in React-Native?
Sincerely appreciate the help!
Try this out.
import React, { Component } from 'react';
import { View, Text } from 'react-native';
import axios from 'axios';
class AlbumList extends Component {
constructor(props){
super(props);
this.state = {
albums: []
};
this.renderAlbums = this.renderAlbums.bind(this);
}
componentWillMount() {
axios.get('https:/rallycoding.herokuapp.com/api/music_albums')
.then(response => this.setState({ albums: response.data }));
}
renderAlbums() {
return (
<View /> // return your Albums here as you need
);
}
render() {
return (
<View>
{this.renderAlbums()}
</View>
);
}
}
export default AlbumList;
I'm using below lib to implement a callback (onSuccess, onError) for every ApiRequest. But I have a problem when update state when event is trigged. I tried to remove all stuffs just keep the base logic. I don't know why it error.
Lib: https://www.npmjs.com/package/react-native-simple-events
Below is my code
ApiRequest.js
import Events from 'react-native-simple-events';
export function login(email, password) {
Events.trigger('LoginSuccess', 'response');
}
Login.js
import React, { Component, } from 'react'
import {
View,
Text,
} from 'react-native'
import Events from 'react-native-simple-events';
import * as request from '../../network/ApiRequest'
class LoginScreen extends Component {
static propTypes = {}
static defaultProps = {}
constructor(props) {
super(props)
this.state = {
status: "new"
}
}
componentDidMount() {
Events.on('LoginSuccess', 'myID', this.onLoginSuccess);
request.login("abc","def")
}
componentWillUnmount() {
Events.rm('LoginSuccess', 'myID');
}
onLoginSuccess(data){
this.setState({ //=>error here
status : "done"
});
}
render() {
return (
<View>
<Text>
{this.state.status}
</Text>
</View>
)
}
}
let me know if you need more information
You need to bind this on the onLoginSuccess method:
Events.on('LoginSuccess', 'myID', this.onLoginSuccess.bind(this));