React Native goBack() not being called correctly - reactjs

My react-native-webview won't go back in any way. Back button press is correctly handled in android and logged in the right way, the WEBVIEW_REF is not null, but even if the "canGoBack" state is true, the webview just won't go back even if able.
I am testing this code in Android
import React, { Component } from "react";
import { BackHandler } from "react-native";
import { WebView } from "react-native-webview";
export default class CustomWebView extends Component {
constructor(props) {
super(props);
this.state = {
canGoBack: false,
}
}
WEBVIEW_REF = React.createRef();
componentDidMount() {
BackHandler.addEventListener("hardwareBackPress", this.handleBackButton);
}
componentWillUnmount() {
BackHandler.removeEventListener("hardwareBackPress", this.handleBackButton);
}
handleBackButton = () => {
if (this.state.canGoBack) {
console.log(this.WEBVIEW_REF.current);
this.WEBVIEW_REF.current.goBack();
}
return true;
}
onNavigationStateChange = (navState) => {
console.log("navState", navState.canGoBack);
this.setState({
canGoBack: navState.canGoBack,
});
};
render() {
return (
<WebView
style={{width:400,height:200}}
source={{
uri: "https://www.google.com/",
}}
ref={this.WEBVIEW_REF}
onNavigationStateChange={this.onNavigationStateChange}
/>
);
}
}

Try like this,
componentDidMount() {
if (Platform.OS === 'android') {
this.backHandler = BackHandler.addEventListener('hardwareBackPress', function () {
return true;
});
}
}
componentWillUnmount() {
this.backHandler.remove();
}

Related

how to use map function with (axios/classhooks) to read from API

import React, { Component } from "react";
import axios from "axios";
class Verifry extends Component {
constructor(props) {
super(props);
this.state = {
s: "0",
user: [],
};
}
/* has title as attribute within the res.data*/
async componentDidMount() {
await axios
.get(http://10.0.0.106:8080/kuwait_elections/api/about_us)
.then((res) => {
const persons = res.data;
this.setState({ user: persons.data.title, s: "4" });
console.log(this.state.user);
});
}
componentDidUpdate() {
// this.state.user.map((u) => {
// return u;
// });
}
render() {
return (
{this.state.user.map((t) => {
return {t.title};
})}
);
}
}
export default Verifry;
Seems your return is not correct. It should be like this.
{
this.state.user.map(({title}) => {
return { title };
})
}
Note: Please format your code properly to make it easier to understand.

React component doesn't update after updating state with redux action

/keywordsActions
import { UPDATE_KEYWORDS } from "./actionTypes";
import queryString from "query-string";
const keywordsArrayFromUrl = () => {
const query = queryString.parse(window.location.search);
if (query.keywords) {
const removeDuplicate = new Set(query.keywords.split(" "));
return Array.from(removeDuplicate);
}
return [];
};
export function updateKeywords() {
return async dispatch => {
dispatch({
type: UPDATE_KEYWORDS,
payload: await keywordsArrayFromUrl()
});
};
}
/keywordReducer
import { UPDATE_KEYWORDS } from "../actions/actionTypes";
export default function(state = [], action) {
switch (action.type) {
case UPDATE_KEYWORDS:
return action.payload;
default:
return state;
}
}
/SearchBar -- React Component
import React, { Component } from "react";
import { withRouter } from "react-router-dom";
//Redux
import { connect } from "react-redux";
import { updateKeywords } from "../store/actions/KeywordsAction";
class Searchbar extends Component {
constructor(props) {
super(props);
this.state = {
keywords : this.props.keywords
keywordsString: this.props.keywords.join(" ")
};
}
componentDidMount() {
this.props.updateKeywords();
console.log(this.props)
setTimeout(() => console.log(this.props), 10);
}
_handleChange = e => {
this.setState({ keywordsString: e.target.value });
};
_handleSearch = value => {
this.setState({ keywordsString: value });
this.props.history.push(`/search?keywords=${value}`);
};
render() {
return (
<Search
className="Searchbar"
placeholder="Cauta prin iBac..."
value={this.state.keywordsString}
onChange={this._handleChange}
onSearch={this._handleSearch}
/>
);
}
}
const mapStateToProps = state => {
return {
keywords: state.keywords
};
};
export default connect(
mapStateToProps,
{ updateKeywords }
)(withRouter(Searchbar));
I want to save the keywords from the Url to the store and then pass it to the Search bar state.
But i dont understand this :
componentDidMount() {
this.props.updateKeywords();
console.log(this.props); // this.props.keywords is empty
setTimeout(() => console.log(this.props), 10); // After 10 ms this.props.keywords is no empty
}
After 10 ms the props of Searchbar gets updated but the component doesn't render again.
Sorry for my question, I am really new to React / Redux. Please let me know what I am doing wrong. Thank you all!
Update :
componentDidMount() {
this.props.updateKeywords();
setTimeout(() => {
this.setState({
keywordsString: this.props.keywords.join(" ")
});
}, 0);
}
This code is also working... but this other is not working
componentDidMount() {
this.props.updateKeywords();
this.setState({
keywordsString: this.props.keywords.join(" ")
});
}
The reason is that componentDidMount is only called once on mount. What you're looking for is either componentShouldUpdate or componentDidUpdate or the render function, all of which are called when your component receives the updated state from redux. You can read here for more information on what these functions do.
https://reactjs.org/docs/react-component.html#updating

How to continue mounting if condition is met?

I am using react and I have componentWillMount which looks like this
componentWillMount() {
axios.get('/user').then(response => {
console.log(response.data.user)
if (response.data.user) {
} else {
this.props.history.replace('/signup');
}
});
}
Notice this line here in the code.
if (response.data.user) {
}
Now, How can I make my container render if the condition is met?
You just need to set the user variable in the component state once you received it in then method, and later you can use it in your render method:
import React from 'react'
class App extends React.Component {
constructor (props) {
super(props)
this.state = { user: null }
}
componentWillMount() {
axios.get('/user').then(response => {
if (response.data.user) {
this.setState({ user: reaponse.data.user )}
} else {
this.props.history.replace('/signup')
}
})
}
render() {
// Do something with the user
if (this.state.user) {
return <div>{this.state.user.name}</div>
}
return <div />
}
}
Hy, render conditionally based on state.
import React from "react";
class ExampleComponent extends React.PureComponent {
state={ user: null }
static getDerivedStateFromProps(nextProps, prevState){
if(!prevState.user && state.user){
this.props.history.replace('/signup');
}
else return null;
}
componentWillMount() {
axios.get('/user').then(response => {
console.log(response.data.user)
if (response.data.user) {
this.setState({ user: response.data.user )}
}
});
}
render() {
const { user } = this.state;
return user ? <div>have user, can return null</div> : <div>loading user</div>
}
}
export default ExampleComponent;

Updated page not getting re-rendered using `history.push` in nested routes

I am using nested route. Parent component shows category list and the child component shows modal. On performing delete action in modal i.e. child, I am redirecting to the parent route using history.push. The component is getting rendered but without re-rendering the component i.e. the record which was deleted still appears in the view, but when I refresh the page the record does not appear. Any suggestions on this?
Here is my code -
CategoryList.js
import React, { Component } from 'react';
import { Route, Link } from 'react-router-dom';
import CustomisedModal from './../../elements/CustomisedModal';
class CategoryList extends Component {
state = {
categories: [],
}
componentDidMount() {
fetch('http://localhost:8080/xxxx')
.then(results => {
return results.json();
}).then(data => {
this.setState({ categories: data.categories });
})
.catch(error => {
this.setState({ error: true });
});
}
deleteCategoryHandler = (id) => {
**//navigate to modal**
this.props.history.replace('/category/delete/' + id);
}
render() {
if (!this.state.error) {
categories = this.state.categories.map(category => {
return (
xxxxx
)
})
}
return (
<Container>
xxxx
<Route path="/category/delete/:id" exact component={DeleteCategory} /> **<!--Nested route-->**
</Container>
);
}
}
export default CategoryList;
CustomisedModal.js
import React from 'react'
import { Button, Header, Modal, Icon } from 'semantic-ui-react';
class CustomisedModal extends React.Component {
constructor(props) {
super(props);
this.state = {
showModal: this.props.props
}
}
onClose = () => {
this.props.props.history.go('/category');
}
deleteCategory = () => {
fetch('http://localhost:8080/xxxx/' + this.props.props.match.params.id , {
method: 'delete'
})
.then(results => {
return results.json();
}).then(data => {
**//Redirect to parent route**
this.props.props.history.go('/category');
})
.catch(error => {
this.setState({ error: true });
});
}
render() {
return (
<Modal> xxxx
</Modal>
)
}
}
export default CustomisedModal;
the problem here is your parent component has the fetch call in componentDidMount. use componentWillReceiveProps with some condition to reload the data after delete action. As the current parent state hold the old data.
Hope this will help
Fixed the issue by updating state on receiving response so that component gets re-rendered
CustomisedModal.js
import React from 'react'
import { Button, Header, Modal, Icon } from 'semantic-ui-react';
class CustomisedModal extends React.Component {
constructor(props) {
super(props);
this.state = {
categories: this.props.props.categories **added categories to state**
}
}
onClose = () => {
this.props.props.history.go('/category');
}
removeByAttr = function (arr, attr, value) {
var i = arr.length;
while (i--) {
if (arr[i]
&& arr[i].hasOwnProperty(attr)
&& (arguments.length > 2 && arr[i][attr] === value)) {
arr.splice(i, 1);
}
}
return arr;
}
deleteCategory = () => {
fetch('http://localhost:8080/xxxx/' + this.props.props.match.params.id , {
method: 'delete'
})
.then(results => {
return results.json();
}).then(data => {
**//Redirect to parent route**
let newArray = this.removeByAttr(this.state.categories, 'id', data.id);
this.setState({ categories: newArray }); **//updated setState**
this.props.props.history.go('/category');
})
.catch(error => {
this.setState({ error: true });
});
}
render() {
return (
<Modal> xxxx
</Modal>
)
}
}
export default withRouter(CustomisedModal);**// added withRouter**

How to handle event when clicking outside of component?

I reactjs I have a component and it has this code to detect whether there is a click outside the component:
export class Cart extends React.Component {
handleClick(e) {
if (!ReactDOM.findDOMNode(this).contains(e.target)) {
console.log('testing=e.target', e.target)
}
}
componentWillMount() {
document.addEventListener('click', this.handleClick, false);
}
componentWillUnmount() {
document.removeEventListener('click', this.handleClick, false);
}
render()
{
return (<div>hello</div>)
}}
However I am getting an error in the findDOMNode statement:
Uncaught Error: Element appears to be neither ReactComponent nor DOMNode
How can I fix this?
You can add id property to the div component, and then refactor the code as follows:
export class Cart extends React.Component {
handleClick(e) {
if (e.target.id === 'div') {
console.log('inside')
} else {
console.log('outside!')
}
}
componentWillMount() {
document.addEventListener('click', this.handleClick, false);
}
componentWillUnmount() {
document.removeEventListener('click', this.handleClick, false);
}
render()
{
return (
<div id="div">
hello
</div>)
}
}

Resources