React Native how to use removeEventListener - javascript

How can I replicate this code in React? I am new to react and I have not been able to get it, thank you very much in advance
<progress id="bar" value="0" max="110"></progress>
<button onclick="increment()" id="increment">one time</button>
<button onclick="unlimited()" id="multiple">multiple</button>
<script>
var puntaje = document.getElementById("bar").value;
document.getElementById("increment").addEventListener("click",increment)
function increment (e)
{ e.target.removeEventListener(e.type,increment);
document.getElementById("bar").value += 10;}
function unlimited (){document.getElementById("bar").value += 10}
</script>

Use state to determine if the button has already been clicked once:
const component = () => {
const [value, setValue] = React.useState(0);
const [hasIncrementedOnce, setHasIncrementedOnce] = React.useState(false);
const increment = () => setValue((current) => current + 10);
const incrementOnce = React.useCallback(() => {
if (!hasIncrementedOnce) {
increment();
setHasIncrementedOnce(true);
}
}, [hasIncrementedOnce])
return (
<>
<progress id="bar" value={value} max="110"></progress>
<button onClick={incrementOnce} id="increment" disabled={hasIncrementedOnce}>one time</button>
<button onClick={increment} id="multiple">multiple</button>
</>
);
}

Related

Svelte variable not updating from localStorage without using setInterval and forcing it

I have an app that stores items into locations in localStorage and then displays the items in HTML.
One of the reasons i wanted to use Svelte was for reactive variables, but whenever I attempt to use a reactive variable that changes whenever localStorage.current_items changes, the ItemList variable doesn't change.
The only way I could get it to work is by using setInterval but that is not a great way to do it. How can I make it so that ItemList changes properly when the localStorage.current_items string changes.
<script lang="ts">
import {
getData,
createItem,
createLocation,
closeItem,
} from './lib/database.js';
import LocationSelector from './lib/LocationSelector.svelte';
import { flip } from 'svelte/animate';
import { writable } from 'svelte/store';
let DB = getData();
// load items from localstorage.items
let ItemList = [];
let Location;
setInterval(() => {
Location = localStorage.current_items;
ItemList = JSON.parse(localStorage.current_items).items;
}, 500);
console.log(ItemList);
let newItem = '';
let filter_showClosed = false;
function addNewItem(e) {
e.preventDefault();
console.log(newItem);
const newItemInput = document.querySelector(
'#newItemInput'
) as HTMLInputElement;
createItem(JSON.parse(Location).id, newItem);
newItem = '';
}
function newItemKeyDown(e) {
if (e.keyCode === 13) {
addNewItem(e);
}
}
</script>
<LocationSelector />
<div class="app">
<input
type="text"
id="newItemInput"
bind:value={newItem}
placeholder="Add a new item"
on:keydown={newItemKeyDown}
/>
<button
id="filter_showClosed"
data-active="false"
on:click={function () {
filter_showClosed = !filter_showClosed;
let el = document.getElementById('filter_showClosed');
if (filter_showClosed) {
el.innerHTML = 'Hide closed';
el.dataset.active = 'true';
} else {
el.innerHTML = 'Show closed';
el.dataset.active = 'false';
}
}}>Show closed</button
>
<!-- <button
id="deleteClosed"
on:click={function () {
let it = items;
for (let i = 0; i < it.length; i++) {
if (it[i].closed == true) {
it.splice(i, 1);
}
}
items = it;
sort_items(items);
}}>Delete all closed</button
> -->
<div class="list">
{#each ItemList as item, index (item.id)}
<div class="item {item.closed}" animate:flip={{ duration: 100 }}>
{#if item.closed == false || (filter_showClosed == true && item.closed == true)}
<div>
<img
src="/up.svg"
class="item-icon"
class:closed={item.closed == true}
alt="move item up in priority"
on:click={function () {
// increaseLevel({ item });
}}
/>
{item.name} ({index})
</div>
<div>
{#if item.closed == false}
<img
src="/close.svg"
class="item-icon"
alt="close item"
on:click={function () {
console.log(Location.id);
closeItem(JSON.parse(Location).id, item.id);
}}
/>
{/if}
</div>
{/if}
</div>
{/each}
</div>
</div>
<style>
</style>
I tried using this writeable method, but that didn't work either as the variable still didn't change.
import { writable } from 'svelte/store';
const ItemList = writable([]);
let Location = {};
let newItem = '';
let filter_showClosed = false;
function addNewItem(e) {
e.preventDefault();
console.log(newItem);
const newItemInput = document.querySelector(
'#newItemInput'
) as HTMLInputElement;
createItem(Location.id, newItem);
newItem = '';
}
function newItemKeyDown(e) {
if (e.keyCode === 13) {
addNewItem(e);
}
}
// Update the Location object with the current value of localStorage.current_items as an object
Location = JSON.parse(localStorage.current_items);
// Update the ItemList store with the new location's items
ItemList.set(Location.items);
You should use a store that fully wraps the access to localStorage.
Something like:
function localStorageStore(key, initial) {
const value = localStorage.getItem(key)
const store = writable(value == null ? initial : JSON.parse(value));
store.subscribe(v => localStorage.setItem(key, JSON.stringify(v)));
return store;
}
Reading and writing is just a regular store, but on initial load the value comes from the storage and on setting the value, it is also written to storage.

scrollTop = scrollHeight not working in chatbot

As part of Technigo bootcamp, my team has created a chatbot and got it to work well! (see it live here) However, when the content is bigger than the chat container a scroll appear and it wont scroll to the last message.
We have tried using (on both function showMessage and showFinalMessage)
chat.scrollTop = chat.scrollHeight
But it does not seem to work as seen on below pic
enter image description here
See JS code here
// All the DOM selectors stored as short variables
const chat = document.getElementById('chat')
const inputWrapper = document.getElementById('input-wrapper')
// Global variables, if you need any, declared here
let stepNumber = 1
// Functions declared here
const botAnswer = (message) => {
showMessage (message, 'bot')
}
const userAnswer = (message) => {
showMessage (message, 'user')
}
// This function will add a chat bubble in the correct place based on who the sender is
const showMessage = (message, sender) => {
console.log(sender)
if (sender === 'user') {
chat.innerHTML += `
<section class="user-msg">
<div class="bubble user-bubble">
<p>${message}</p>
</div>
<img class="profile-pic" src="assets/user-img.jpeg" alt="User" />
</section>
`
} else if (sender === 'bot') {
chat.innerHTML += `
<section class="bot-msg">
<img class="profile-pic" src="assets/bot-img.jpeg" alt="Bot" />
<div class="bubble bot-bubble">
<p>${message}</p>
</div>
</section>
`
}
// This little thing makes the chat scroll to the last message when there are too many to be shown in the chat box
chat.scrollTop = chat.scrollHeight
}
const nextStep = (message) => {
console.log( 'stepNumber', stepNumber)
if (answerNumber === 1) {
userAnswer (message)
setTimeout (() => showPlace(message),1000)
} else if (answerNumber === 2) {
userAnswer (message)
setTimeout (() => showVibe(message),1000)
} else if (answerNumber === 3) {
userAnswer (message)
setTimeout (() => showOutfit(message),1000)
}
}
// Starts here
const showMood = () => {
answerNumber = 1
botAnswer(`Welcome! How's the party mood?`)
inputWrapper.innerHTML = `
<div class="slider-container">
<div class="emoji-container">
<p class="emoji">🍺</p>
<p class="emoji">🍻</p>
<p class="emoji">🍹</p>
<p class="emoji">🍸</p>
<p class="emoji">🍷</p>
<p class="emoji">🍾</p>
</div>
<input id="sliderinput" type="range" min="1" max="100" value="50" class="slider">
</div>
`
document.getElementById('sliderinput')
.addEventListener('mouseup', () => nextStep ('This is my mood!'))
}
const showPlace = () => {
answerNumber++
botAnswer(`Good to know! But where's the party at?`)
inputWrapper.innerHTML = `
<button id="nightclubBtn">Nightclub</button>
<button id="cocktailBtn">Cocktail bar</button>
`
document.getElementById('nightclubBtn')
.addEventListener('click', () => nextStep('Nightclub'))
document.getElementById('cocktailBtn')
.addEventListener('click', () => nextStep('Cocktail bar'))
}
const showVibe = (place) => {
answerNumber++
if (place === 'Nightclub') {
botAnswer(`Are we talking Berghain or Studio54?`)
inputWrapper.innerHTML = `
<button id="berghainBtn">Berghain</button>
<button id="studio54Btn">Studio 54</button>
`
document.getElementById('berghainBtn')
.addEventListener('click', () => nextStep('Berghain'))
document.getElementById('studio54Btn')
.addEventListener('click', () => nextStep('Studio 54'))
} else {
botAnswer(`In the mood for Cosmopolitan or Old Fashioned?`)
inputWrapper.innerHTML = `
<button id="cosmoBtn">Cosmopolitan</button>
<button id="oldfashionBtn">Old Fashioned</button>
`
document.getElementById('cosmoBtn')
.addEventListener('click', () => nextStep('Cosmopolitan'))
document.getElementById('oldfashionBtn')
.addEventListener('click', () => nextStep('Old fashioned'))
}
}
const showOutfit = (outfit) => {
answerNumber++
botAnswer(`I got the perfect outfit for you! Party on!`)
const showFinalMessage = () => {
chat.innerHTML += `
<section class="bot-msg">
<img class="profile-pic" src="assets/bot-img.jpeg" alt="Bot" />
<div class="bubble bot-bubble final">
<img class="outfit-gif" id="outfitGif" src=""/>
</div>
</section>
`
chat.scrollTop = chat.scrollHeight
}
if (outfit === 'Berghain') {
showFinalMessage()
document.getElementById("outfitGif").src = "assets/berghain.gif"
}
else if (outfit === "Studio 54") {
showFinalMessage()
document.getElementById("outfitGif").src = "assets/studio54.gif"
}
else if (outfit === "Cosmopolitan") {
showFinalMessage()
document.getElementById("outfitGif").src = "assets/cocktail.gif"
}
else if (outfit === "Old fashioned") {
showFinalMessage()
document.getElementById("outfitGif").src = "assets/oldfashioned.gif"
}
inputWrapper.innerHTML = ""
}
setTimeout(showMood, 1000)
For reference, also see CSS code for main och chat here.

Can't understand this behaviour

I have a simple notes app and delete isn't working properly, even though state is correctly updated.
The state is being updated correctly as I can see on the console.
But all the notes including and after that note that I click delete on are getting deleted on the DOM for some reason.
For example if I have 3 notes ["hello","hi","hey"], if I delete the second note("hi"), the state shows the correct notes ["hello","hey"] but both "hi" and "hey" are deleted on the page not just "hi" like it was supposed to.
I can't understand where I've gone wrong, so I'd like to correct it.
App.js:
handleDelete = (note_id) => {
const id = 'display-' + note_id;
console.log(id);
document.getElementById(id).style.display = 'none';//remove element
//delete the note and update state
const newNotesList = this.state.notesList;
newNotesList.splice(note_id,1);
this.setState({
notesList : newNotesList
})
console.log(this.state.notesList)
}
Display.js:
render(){
const notesList = this.props.notesList;
const displayNotes = notesList.map( (note,note_id) =>
<div id={ 'display-' + note_id } className="display">
{/*some code*/}
<button type="button" className="delete-button"
onClick = { () => this.props.handleDelete(note_id) } > Delete </button>
</div> );
return <div>{displayNotes}</div>;
}
do like this
// don't mutation object
// App.js
handleDelete = (note_id) => {
//delete the note and update state
const newNotesList = this.state.notesList.filter((item, index)=> index !== note_id)
this.setState({
notesList : newNotesList
})
}
// Display.js
render(){
const notesList = this.props.notesList;
const displayNotes = notesList.map( (note,note_id) =>
<div>
{/*some code*/}
<button type="button" className="delete-button"
onClick = { () => this.props.handleDelete(note_id) } > Delete </button>
</div> );
return <div>{displayNotes}</div>;
}
==== here is the reason ========
at first the state.note is ["hello","hi","hey"], in the function of handleDelete you delete "hi" and make the id of dispaly-1's display become to hidden, so when react render the state.note === ["hello","hey"] the element of "hey"'s id become dispaly-1 so "hey" will be hidden. you will only see "hello"
handleDelete = (note_id) => {
// this.state.notesList === ["hello","hi","hey"]
const id = 'display-' + note_id;
console.log(id);
// the problem is u hidden the next element
// 1. newNotesList.splice(note_id,1);
// 2. document.getElementById(id).style.display = 'none'
// two methods choose one or you will hidden two elements
document.getElementById(id).style.display = 'none';//remove element
//delete the note and update state
const newNotesList = this.state.notesList;
newNotesList.splice(note_id,1);
this.setState({
notesList : newNotesList
})
console.log(this.state.notesList)
// for example
// the `this.state.notesList` new is ["hello","hey"]
}
notesList.map( (note,note_id) =>
// `note` is ["hello","hey"] , u don't need hidden the `2rd` element
//you have been delete 'hi' ` the id of `display-1`'s display ==='hidden'
// now "hey"'s id is `display-1`
<div id={ 'display-' + note_id } className="display">
{/*some code*/}
<button type="button" className="delete-button"
onClick = { () => this.props.handleDelete(note_id) } > Delete </button>
</div> );
``

How to replace item while scrolling?

I need to change navbar when scrolling a page. How to catch the moment when to change it? How to do it right, in accordance with the concepts of React? As far as I know, use getElementById is that bad tone?
const useState = React.useState
const useEffect = React.useEffect
const Component = () => {
const [topNavbarHide, setTopNavbarHide] = useState(true);
useEffect(() => {
window.addEventListener('scroll', function () {
let navbarSize = document.getElementById('navbar').offsetHeight;
console.log("navbarSize " + navbarSize + "px");
let scrollTop = document.documentElement.scrollTop;
console.log("scrollTop " + scrollTop);
if (scrollTop > navbarSize) {
setTopNavbarHide(false)
} else {
setTopNavbarHide(true)
}
console.log(topNavbarHide);
});
});
return (
<div>
<div id={"navbar"} className="navbar">
<div
className={(topNavbarHide) ? "topNavbar" : "topNavbar hide"}>topNavbar
</div>
<div className="bottomNavbar">bottomNavbar</div>
</div>
<div className="box"></div>
<div className="box1"></div>
<div className="box2"></div>
<div className="box"></div>
<div className="box1"></div>
</div>
)
};
ReactDOM.render(
<Component/>,
document.getElementById('root')
);
https://codepen.io/slava4ka/pen/wvvGoBX
It is perfectly fine to add an event listener, in the way that you are currently doing it, to a React hook. The way that you are doing it is the correct way.
There is another, more simpler way with react-waypoint. You can place invisible waypoints on your screen and it can trigger events when waypoint enter or leave screen.
For example:
const Component = () => {
const [topNavbarHide, setTopNavbarHide] = useState(true);
return (
<div>
<div id={"navbar"} className="navbar">
<div className={topNavbarHide ? "topNavbar" : "topNavbar hide"}>
topNavbar
</div>
<div className="bottomNavbar">bottomNavbar</div>
</div>
<Waypoint
onEnter={() => setTopNavbarHide(true)}
onLeave={() => setTopNavbarHide(false)}
/>
<div className="box" />
<div className="box1" />
<div className="box2" />
<div className="box" />
<div className="box1" />
</div>
);
};
It is basically working like your example.
https://codesandbox.io/s/hungry-hodgkin-5jucl

Passing onclick event in template literal

I'm trying to pass url through onclick event, its not working.
there is <body onload="displayBookmarks()"> to initialise displayBookmarks function as soon as the page gets loaded
function deleteBookmark(url){
alert(url);
};
function displayBookmarks(){
bookmarksResults.innerHTML = "";
for (let a in bookmarks){
let name = bookmarks[a].name;
let url = bookmarks[a].url;
bookmarksResults.innerHTML += `<div class="well"> <h3> ${name} <a class="btn btn-default" target="_blank" href=${url} >Visit</a> <a onclick=${deleteBookmark(url)} class="btn btn-danger" >Delete</a></h3></div>`
}
}
The main problem is onclick=${deleteBookmark(url)}
As soon as the page loads it starts displaying the url but I want to to be shown only when delete button is pressed.
I've found that there is another way to do this with encapsulation. I don't know if I would recommend doing it like this at all but since you've asked the question.
const app = document.getElementById("app");
const button = ((app) => {
let _url;
const _log = (data) => {
console.log(data);
}
let _content = `<button onclick="(${_log})('${_url}')">test</button>`;
const _setContent = () => {
_content = `<button onclick="(${_log})('${_url}')">test</button>`;
}
const _setUrl = (url) => {
_url = url;
}
return {
setUrl: (url) => {
_setUrl(url);
_setContent();
},
render: () => {
app.innerHTML = _content;
}
}
})(app)
const url = 'www.something.com';
button.setUrl(url);
button.render();
<section id="app">...</section>
const markUp = `
<button onclick="myFunction()">Click me</button>
`;
document.body.innerHTML = markUp;
window.myFunction = () => {
console.log('Button clicked');
};

Categories

Resources