I'm trying to understand how reactivity should work, but I cannot figure out why some things work how they work.
Svelte REPL with the code: https://svelte.dev/repl/aa0821cd95c54708b2d12a05bf74577e?version=3.49.0
I created a simple app:
App.svelte:
<script>
import { numbers } from './store.js'
function copy() {
$numbers.copied = $numbers.selected
}
function select(i) {
console.log("Selected: " + i)
$numbers.selected = i
}
</script>
<button on:click={select(1)}>
1
</button>
<button on:click={select(2)}>
2
</button>
<button on:click={select(3)}>
3
</button>
<button on:click={copy()}>
Copy
</button>
<h1>
Selected: {$numbers.selected}
</h1>
<h1>
Copied: {$numbers.copied}
</h1>
store.js:
import { writable } from 'svelte/store'
export let numbers = writable({
selected: null,
copied: null
})
From this, I was expecting:
On launch, store values stay as null
On every button click, $store.selected changes to proper value
$store.copied updates its value only when Copy button is clicked
Instead:
On launch, select function is called 3 times, once for every button with its argument
$store.selected and $store.copied both have value 3 which cannot be changed by clicking buttons
When clicking buttons, select function is not called
Your event handlers are just wrong. You are calling the functions instead of passing them.
You need something like on:click={() => select(1)}. For copy you could also pass it as is because it has no arguments: on:click={copy}.
Related
I am a beginner in React.js and I'm trying to implement a delete functionality for an app. On clicking the button, the form gets submitted and the function runs, however it shows an error in the console which is there for a split second so I couldn't read it. I have tried setTimeout to atleast see the error but it has no effect. The error just appears for a fraction of a second in the console and then disappears. The code is:
const Note = ({object}) => {
const {title, desc} = object;
const handleDel = (e, object)=>{
e.preventDefault();
console.log(object)
}
return (
<>
<div className="single-note">
<div>
<h1>{title}</h1>
<p>{desc}</p>
</div>
<form onSubmit={()=>handleDel(object)}>
<button type="submit" className="submit">
<FaRegTrashAlt/>
</button>
</form>
</div>
</>
)
}
export default Note
I guess you missed to pass the event and it is trying to invoke preventDefault on the object param that is passed. Try the below code:
onSubmt={(e) => handleDel(e,object)}
I am trying to set an array to a state hook. Basically I want to keep a track of a per-row (of grid sort of) Edit Dialog Open State. Basically per row, I have a Edit button, launches a . As all seems rendered initially, I am trying to manage the show hide by keeping an array in the parent grid component. When user clicks on the Edit button, per row, I want to pass the rowData as props.data and want to provide the Edit functionality.
To keep the state of the editDialogs (show/hide), I am making a array of objects useState hook as follows:
const [editDialogsModalState, setEditDialogsModalState] = useState([{}]); // every edit dialog has it's own state
...
function initializeEditDialogsModalState(dataSet) {
let newState = [];
dataSet.map((item) => newState.push({ id: item.id, state: false }));
return setEditDialogsModalState(newState); // **PROBLEM->Not setting**
}
function addUDButtons(currentRowDataMovie) { // my edit/delete button UI code
const currRowDataId = currentRowDataMovie.id;
return (
<span>
<button
type="button"
className="btn btn-info"
onClick={() => setEditDialogsState(currRowDataId)}
>
Edit
</button>
{editDialogsModalState[currRowDataId].state && ( // **PROBLEM->null data even after set call**
<EditMovieComponent
open={editDialogsModalState[currRowDataId].state}
onToggle={toggleEditDialogsModalState(currentRowDataMovie)}
movie={currentRowDataMovie}
/>
)}
}
......
function buildGrid() {
{
if (!ready) {
// data is not there, why to build the grid
return;
}
initializeEditDialogsModalState(movies);
...........
}
However not able to get the editStates. A screen shot from debugger where I can see the movies (REST output), ready, but not the editDialogsModalState state array.
In general, is there a better ways of implementing such per-row basis functionality where on click of a button I want to open a React-bootstrap and pass the row-specific dataitem for doing operations ? (I am learning React, so may not not yet fully aware of all pointers).
Thanks,
Pradip
import React from "react"
import { useState } from "react"
export default function App() {
const [count, setCount] = useState({ c: 0 })
console.log(new Date().toString())
console.log(`Object output ${count.c}`)
return (
<div>
<p>{new Date().toString()}</p>
{console.log(new Date().toString())};
<br />
<p>You clicked Object counter {count.c} times</p>
<button onClick={() => setCount({ ...count, c: count.c + 1 })}>
Click me
</button>
<p>You clicked Object counter {count.c} times</p>
<button onClick={() => setCount(count)}>Click me</button>
</div>
)
}
In the above React code after updating the count by clicking the first button executes log and re-renders but immediately after that clicking on second button for the first time executes the console logs in the function but do not re-render the component as the date value remains the same for this event and further click on the second button do not execute this log can anyone explain why?
Edit: explain why console logs are executed when there is no state change in second button?
(note: this happens only when first button is clicked before this which changes the state and also console logs for second button is logged only for its first click)
Console-logs-screenshot
On setCount(count) you don't change the state, React rerenders only on state change (shallow comparison).
Doing setCount({...count}) will rerender with the same data.
Read more on Reconciliation
I have following code
my code
I have a button "add", and when I am clicking "new user" was added in my array.
But it works only the first time when I am clicking second, third.... times nothing was happening.
how many times I click so many times "new user" should be added into an array.
like this.
I am using functional components and useState hook.
Please help me resolve that problem
Put the <NewUser /> inside of the setAddNew([...addNew])array. Check the following code:
function add() {
setAddNew([...addNew, <NewUser />]);
}
Try this code in your Add.jsx
import React, { useState } from "react";
function Add() {
const [addNew, setAddNew] = useState([]);
function add() {
// HERE is the change, you need to keep the previous values
setAddNew([...addNew, <NewUser />]);
}
return (
<div>
<button onClick={add}>Add </button>
<div> {addNew} </div>
</div>
);
}
const NewUser = () => {
return (
<p>
<div>New User </div>
</p>
);
};
export default Add;
addNew - is the state, in this case, an array.
setAddNew - is the function to handle the State, but you need to handle the logic
This is happening because you are resetting the value of array for pushing new value to it you have to use
setAddNew((old) => [...old, <NewUser />]);
this will copy your old array and will also insert the new element to it
In the Add.jsx what needs to change is:
function add() {
setAddNew(<NewUser />);
}
into...
function add() {
setAddNew([...addNew, <NewUser />]);
}
The previous function would keep resetting <NewUser/ > with itself, thus being only 1.
When adding the previous addNew state via ...addNew within an array [], thus being [...addNew, <NewUser />], this will take the previous state of addNew and add a <NewUser /> on top of that.
I have a drop down component that looks like this:
{...}
this.state = {
isVisible: false
}
}
toggleDisplay() {
this.setState({isVisible: !this.state.isVisible});
}
render() {
return (
<div>
<button onClick={this.toggleDisplay()}>click</button>
{this.state.isVisible ? <MenuElements toggleDisplay={this.toggleDisplay} /> : '' }
</div>
)
}
}
"MenuElements" is just a ul that has a li. On another page i am using this component multiple times, so whenever i click on the button, "MenuElements" is shown for each click. The problem is that i want only one component to be displayed. So if a MenuElements component is already displayed, if i click on another button, it closes the previous component, and opens the second one.
How could this be implemented in my code?
Thanks.
You will somehow need to have a single state that defines which MenuItem is displayed. You could go with a global state with something like Redux, but if you are trying to build a reusable component, I guess it'd be best to wrap all of the MenuItem components in a parent component and keep a state there. That, I think, is the React way of doing it. Read this for an idea of how to design components: https://facebook.github.io/react/docs/thinking-in-react.html.
BTW, I think there is an error in the Button onClick handler. It should be:
<button onClick={this.toggleDisplay.bind(this)}> // or bind it somewhere else
Also, the correct way to change state based on previous state is this:
// Correct
this.setState((prevState, props) => ({
counter: prevState.counter + props.increment
}));
// Wrong
this.setState({
counter: this.state.counter + this.props.increment,
});
I'd say this is du to the context of your callbacks. Have you tried forcing the context ?
<div>
<button onClick={this.toggleDisplay.bind(this)}>
click
</button>
{this.state.isVisible ?
<MenuElements toggleDisplay={this.toggleDisplay.bind(this)} />
: '' }
</div>