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
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.
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.
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> );
``
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
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');
};