How to toggle state in React Native - javascript

I am developing a light weight project using React Native, and I encountered some setbacks, I couldn't figure it out. :(
I have a page that contains a Yes and a No button and a Yes/No render area, users will be able to click on either of the buttons. According to the users' choice, an avatar will appear in the correct render area (click yes, the avatar will be in the Yes area...). But one user can only be able to click once. I am trying to solve this using state and setState, but couldn't get it to work.
I have:
this.state = {invitedState : false}
and a function (part)
onPress={() => {
if (this.state.invitedState) {
onPress();
}
this.setState(prevState => ({
invitedState: !prevState.invitedState,
}));
}}
Should I not use setState to solve this problem?
thanks!

I think I understand your problem. Something like this?
state = {
toggleUI: true,
userToggled: false
};
handleToggleUI = e => {
this.setState(currentState => {
if ( this.state.userToggled === false ) {
return {
toggleUI: !currentState.toggleUI,
userToggled: true
};
}
});
};

You could try:
onPress{() => {
let tempVar = this.state.invitedState ? false : true;
this.setState({invitedState: tempVar});
}

Related

component in react native gets updated itself in RefreshControl

So I am trying to implement a pull to refresh feature in my app. And to say I have successfully implemented this in my Android platform where (in simulator) If I pull down (by mouse) then the refreshing indicator will stay visible until I leave the mouse click and the component will not update until the mouse click as well. It will update the component view when I leave the mouse click and refreshing indicator will be hidden in 2 sec. The similar thing is not exactly working as expected in ios, so when I pull down the screen, the component somehow updates even when I haven't left the mouse click. I have given it a googling but probably haven't been able to find the right search keyword.
Below is code snippet of mine. Thanks in advance.
render() {
const { loadingCart } = this.props;
return (
<View style={styles.container}>
<ScrollView
style={styles.scrollView}
contentContainerStyle={styles.contentContainer}
contentInsetAdjustmentBehavior="automatic"
horizontal={false}
refreshControl={this._renderRefreshingControl()}
>
{this._renderProduct()}
{loadingCart && this._renderLoadingCart()}
</ScrollView>
{this._renderCartButton()}
{this._renderAddToCartPopover()}
</View>
);
}
_renderRefreshingControl = () => {
const { refreshing } = this.state;
return (
<RefreshControl refreshing={refreshing} onRefresh={this._handleRefreshingControlVisibility} />
);
};
_handleRefreshingControlVisibility = async () => {
const { fetchProductByCode, navigation } = this.props;
this.setState({
refreshing: true,
});
const resultAction = await fetchProductByCode('38186');
if (resultAction.type === PRODUCT_FETCH_SUCCESS || resultAction.type === PRODUCT_FETCH_FAILURE) {
this.setState({
refreshing: false,
});
};
};
I hope I have been able to clarify my question :-)
Try this out:
_handleRefreshingControlVisibility = () => {
this.setState({ refreshing: true });
setTimeout(function() {
// here do what you want
}, 1500);
};
So the RefreshControl was working as expected, I had a loading flag in my render method, somehow this would be set to false when then refreshing is set true in this.setState({ refreshing: true, })
eventually removing the loading flag solved my issue.

React object property setting broken

I think I found a react bug?
I have 2 functions to show my modal, first I have a modal state like this:
state = {
modal: {
requestPopUp: {
visible: false,
},
},
};
and 2 functions to hide/show it
// Helper Methods
handleOpenModal = name => {
const modal = { ...this.state.modal };
modal[name].visible = true;
this.setState({ modal });
};
handleCloseModal = name => {
const modal = { ...this.state.modal };
modal[name].visible = false;
this.setState({ modal });
};
handleOpenModal works fine, however, handleCloseModal does not, it runs but doesnt alter the state.
modal[name].visible = false; This line specifically does nothing, I logged (modal,name) after it and it stays true and not false, how can I fix this??
Edit: I call my functions here:
<div className="card request p-3" onClick={() => this.handleOpenModal("requestPopUp")}>
Which works fine
and here
<Modal show={modal.requestPopUp.visible} onHide={() => this.handleCloseModal("requestPopUp")}>
Which also calls the function properly but it's never set as false as per the function logic.
My react version is "react": "^16.12.0"
Try to avoid mutating the object props directly e.g (obj[prop] = value) since its antI-pattern ... Use destructering as my example below:
On a different note, no need to write the code twice, you can reuse the same function, and pass an extra param to define if u wanna close/open:
handleModalClick = (name, visible) => {
this.setState({
modal: {
...this.state.modal,
[name]: {...this.state.modal[name], visible }
}
})
}

Snackbar error message within if statement

I have an if statement that errors out if a user selects a file format that is not valid, however, it is currently done within js as an alert, I would like to change this to Material UI's snackbar error message. However I am having trouble doing so, the code below.
let file = document.getElementById("file-upload");
const onSelectFile = e => {
setFieldValue(e.target.name, e.target.files[0]);
setFieldTouched(e.target.name, true, false);
let fileName = file.value;
if (
fileRestrict.findIndex(item => fileName.toLowerCase().endsWith(item)) >= 0
) {
//TODO
} else {
{
LongTextSnackbar;
}
file.value = "";
}
};
function LongTextSnackbar() {
return (
<div className={classes.root}>
<SnackbarContent
className={classes.snackbar}
message={"error error error"}
/>
</div>
);
}
I have tried to imitate Mat UI's `snackbar, but to no avail, inside the else, I need to call another component of material UI's somehow, any suggestions on how I could do this?
Maybe check this library https://www.polonel.com/snackbar/
Usage is simple like this:
Snackbar.show({text: 'Example notification text.'});
Patch this into your code-
Set initial state of snackbar to closed:
state = {
snackOpen: false
}
Logic to open the snackbar by setting state:
let file = document.getElementById('file-upload');
const onSelectFile = e => {
setFieldValue(e.target.name, e.target.files[0]);
setFieldTouched(e.target.name, true, false);
let fileName = file.value;
if (
fileRestrict.findIndex(item => fileName.toLowerCase().endsWith(item)) >= 0
) {
} else {
this.setState({ snackOpen: "You have tried to upload an unsupported file type. Allowed file types are ${fileRestrict}"})
file.value = '';
}
};
Need to render the snackbar as shown:
render() {
return (
<Snackbar message={this.state.snackOpen} close={() => this.setState({ snackOpen: false })} />
)
}
Note:
I have not tested this, just plugged a snackbar in to demonstrate
how it needs to be done.
The material-ui Dialog component is more appropriate for this use case.

I fail to setState my ReactJS state dynamically with a function

I'm trying to set the display of my ReactJS component dynamically.
Basically the game is the following : the user push a button, then the value of the affiliate state is set to true. Allowing to handle the displaying of the buttons.
However my state doesn't changes when I push a button, despite I log it after the change would have occurred. However I have set my state. I wonder what going wrong.
Here my tiny snippet, easy testable and reproducible :
https://codesandbox.io/s/21963yy01y
Here my snippet.js :
export default class App extends React.Component {
state = {
displaySelection: false,
displayCreate: false,
displayUpdate: false,
displayDelete: false,
}
viewSelection = (e) => {
e.preventDefault();
Object.keys(this.state).map((key, index) => {
// console.log("key value: ", key)
console.log("target name: ", e.target.name)
if (key === e.target.name) {
console.log(e.target.name, " set to true =)")
return this.setState({ [e.target.name]: true }, console.log("display state: ", this.state))
} else {
this.setState({ [e.target.name]: false })
}
});
}
render() {
return (
<div className="App">
<button onClick={this.viewSelection}> Launch the Object.keys function =) splay</button>
<div >
<button name="displayCreate" onClick={this.viewSelection}> Create </button>
<button name="displayUpdate" onClick={this.viewSelection}> Update </button>
<button name="displayDelete" onClick={this.viewSelection}> Delete </button>
<button name="displaySelection" onClick={this.viewSelection}> O </button>
</div>
</div>
);
}
}
Why when I push a button the state of this button doesn't change ?
Any hint would be great,
thanks
Found a flaw in your logic. In your else statement in your viewSelection function, you have:
else {
this.setState({ [e.target.name]: false });
}
So in every iteration of the loop, you are setting the target that was clicked to false in state. You can solve that by changing e.target.name to key, like so:
else {
this.setState({ [key]: false });
}
So that way you're only changing the key that isn't the current target. But this is still inefficient because you're still running setState 4 times (1 for each key in state). One more efficient way to achieve what you're looking for is to have an object (essentially a copy of what's in state) with the keys set to false by default. Then take the target from the click and set that to true, like so:
viewSelection = e => {
e.preventDefault();
let newValues = {
displaySelection: false,
displayCreate: false,
displayUpdate: false,
displayDelete: false
};
newValues[e.target.name] = true;
this.setState(newValues);
}

Click outside of clickable components in React

I have a basic component that looks as follows.
class List extends React.Component {
constructor() {
super(...arguments);
this.state = {
selected: null,
entities: new Map([
[0, { 'name': 'kot'} ],
[1, { 'name': 'blini'} ]
])
};
}
render() {
return (<div>
<ul>{this.renderItems()}</ul>
</div>)
}
renderItems() {
return Array.from(this.state.entities.entries()).map(s => {
const [ id, entry ] = s;
return <li
key={id}
onClick={() => this.setState(state => ({ selected: id }))}
style={{
color: id === this.state.selected ? 'red' : 'black'
}}
>{entry.name}</li>
})
}
}
This works in order to allow me to click on any element and select it. A selected element will appear red. codepen for easy editing.
However, I want behavior that will unset any currently selected item if a click event was found that was not one of these <li> elements.
How can this be done in React?
In your List component, You can add
componentDidMount() {
window.addEventListener("click", (e) => {
let withinListItems = ReactDOM.findDOMNode(this).contains(e.target);
if ( ! withinListItems ) {
this.setState({ selected: null });
}
});
}
And in your renderItems, change onClick to
onClick={ (e) => {
// e.stopPropagation();
this.setState({ selected: id });
}
}
You can checkout this codepen http://codepen.io/anon/pen/LRkzWd
Edit:
What #kubajz said is true, and hence i have updated the answer.
Random User's answer is correct, it may have one flaw - it relies on stopPropagation and there is possibility that some piece of code may no longer work as expected - imagine collecting user's behaviour on page and sending metrics somewhere - stopPropagation will prevent bubbling, thus click is not recorded. Alternative approach is to check what was clicked in event.target: http://codepen.io/jaroslav-kubicek/pen/ORXxkL
Also there is nice utility component for listening on document level: react-event-listener

Categories