React handleClick button throwing error while using hooks - javascript

import React, {useState} from "react"
const App = () => {
const {loggedIn, setLoggedIn} = useState(false)
const handleClick = () => {
setLoggedIn(!loggedIn)
}
return (
<div>
<h1>You are {loggedIn ? 'logged in' : 'logged out'}</h1>
<button onClick={handleClick}>{loggedIn ? 'Log Out' : 'Log In'}</button>
</div>
)
}
export default App
I was writing some code using hooks, and when I click on the button, nothing happens and console shows unknown error message.
I tried changing it to:
() => handleClick
handleClick()
but they all don't work.
What is wrong with the code?

The problem is useState is returning with [] instead of {}.
You should have the following instead:
const [loggedIn, setLoggedIn] = useState(false);
+1 suggestion:
Also it is better to use the callback option when using setLoggedIn in order to capture the previous version of the state as the following:
const handleClick = () => {
setLoggedIn(prev => !prev);
}
I hope this helps!

change const {loggedIn, setLoggedIn} = useState(false)
To : const [loggedIn, setLoggedIn] = useState(false)
Dont use {} to declare useState variable and its setter function use [] these instead.

You are destructuring the state value and change handler incorrectly. It returns a tuple so you need to get the values like this:
const [loggedIn, setLoggedIn] = useState(false)

Related

useState variable is one step behind its assignment

Sorry in advance if the question is a bit vague, still quite new to JS and react. Anyways, my problem is that in the following code the newFilter state hook is one step behind the event.target.value, which should have been assigned to newFilter at onChange, could anyone enlighten me why the newFilter gets updated one step later?
Output in console from console.log, when input change happens:
The code:
function App() {
const [countries, setCountries] = useState([]);
const [newFilter, setNewFilter] = useState('');
const [allCountries, setAllCountries] = useState([]);
useEffect(() => {
axios.get("https://restcountries.com/v3.1/all").then((response) => {
setAllCountries(response.data);
});
}, []);
const handleFilterChange = (event) => {
setNewFilter(event.target.value);
console.log("this is event.target.value", event.target.value)
console.log("this is the newFilter", newFilter)
if (event.target.value) {
let countriesToShow = allCountries.filter((country) =>
country.name.common.toLowerCase().match(event.target.value.toLowerCase())
);
setCountries(countriesToShow);
}
};
return (
<div>
<strong>
<p>Find countries</p>
</strong>{" "}
<input value={newFilter} onChange={handleFilterChange} />
</div>
);
}
export default App;
React state updates are asynchronous & are not run immediately (kind of like setTimeout(func , 0).
See https://reactjs.org/docs/state-and-lifecycle.html#state-updates-may-be-asynchronous.
Hence when you update a state property using its previous value, you should use the callback argument for the state setter.
handleFilterChange = (event) => {
this.setState((state)=> {
newFilter: event.target.value,
countries: (event.target.value)?allCountries.filter(...):allCountries
});
}

is it possible to change the useState value without rendering? React

I need to change the useState without rendering the page.
First is it possible?
const UsersComponent = ({valueProp}) => {
const [users, setUsers] = useState(valueProp);
const [oldUsers, setoldUsers] = useState(value);
const allUsers = useSelector((state) =>
state.users
);
useEffect(() => {
dispatch(getUsersData());
}, [dispatch]);
useEffect(() => {
// assign users to state oldUsers
}, [dispatch]);
const onClickMergeTwoArrayOfUsers = () => {
let oldUsers = collectData(oldUsers);
const filteredUsers = intersectionBy(oldUsers, valueProp, "id");
setUsers(filteredUsers); // most important
console.log("filteredUsers", filteredUsers); // not changed
};
I tried everything nothing helps me.
useEffect(() => {
let oldUsers = collectData(oldUsers);
const filteredUsers = intersectionBy(oldUsers, valueProp, "id");
setUsers(filteredUsers); // most important
}, [users]); // RETURN INFINITIVE LOOP
I am also try ->
useEffect(() => {
let oldUsers = collectData(oldUsers);
const filteredUsers = intersectionBy(oldUsers, valueProp, "id");
setUsers(filteredUsers); // most important
}, []);
Load only one and that doesn't mean anything to me..
I am try with useRef ,but that doesn't help me in this case.
I will try to explain the basis of the problem.
I need to get one get data. After that get on the click of a button, I need to merge oldUsers and users without rendering, change the state. That is problem.
If there is no solution to this problem, tell me what I could do to solve the problem?
I am googling but without succes ... I am also try this solution from interent ->
const [state, setState] = useState({});
setState(prevState => {
// Object.assign would also work
return {...prevState, ...updatedValues};
});
no work.
I am also try with ->
const [state, setState] = useState(() => {
const initialState = someExpensiveComputation(props);
return initialState;
});
Here is problem because I need to asynchronous get only after that can I looping.
Using a ref is probably a better option for whatever it is you're ultimately trying to do.
Yes, it is possible, but it violates one of the core rules of React state: Do Not Modify State Directly.
React compares state values using Object.is equality, so if you simply mutate an object in state instead of replacing it with a new value that is not object-equal, then the state "update" will not cause a re-render (but this is considered a bug in your program!). Anyway, this is how you'd do it:
<div id="root"></div><script src="https://unpkg.com/react#17.0.2/umd/react.development.js"></script><script src="https://unpkg.com/react-dom#17.0.2/umd/react-dom.development.js"></script><script src="https://unpkg.com/#babel/standalone#7.17.1/babel.min.js"></script>
<script type="text/babel" data-type="module" data-presets="env,react">
const {useCallback, useState} = React;
function Example () {
const [state, setState] = useState([1]);
const logState = useCallback(() => console.log(state.join(', ')), [state]);
// Don't actually do this!!!
const mutateState = () => {
setState(arr => {
arr.push(arr.at(-1) + 1);
return arr;
});
};
return (
<>
<div>{state.join(', ')}</div>
<button onClick={mutateState}>Mutate state</button>
<button onClick={logState}>Log state</button>
</>
);
}
ReactDOM.render(<Example />, document.getElementById('root'));
</script>

simple toggle hook in react

I'm having problem abstracting my toggle function out to a hook. I can make the toggle right but something is wrong in this hook code:
import { useState, useCallback } from "react";
const useToggle = (initialValue = false) => {
const [value, setValue] = useState(initialValue);
const toggle = useCallback((defaultValue) => {
defaultValue !== undefined
? setValue(defaultValue) //set true or false
: setValue((value) => !value); //if param is not supplied, toggle the value
}, []);
return [value, toggle];
};
export default useToggle;
https://codesandbox.io/s/goofy-swartz-ztdfb?file=/src/App.js
what's wrong?
On writing this code:
<button onClick={toggle}>toggle</button>
You actually are passing the event object to toggle function.
onClick={(event) => toggle(event)}
// Same
onClick={toggle}
And in your custom hook, you have the condition defaultValue !== undefined which will result in a truthy value.
Therefore you should do:
<button onClick={() => toggle()}>toggle</button>
And for your notice you can just use useReducer instead of custom hook:
const [value,toggle] = useReducer(p=>!p, false);
Example of useToggle
const useToggle = (initialValue = false) => {
const [value, setValue] = useState(initialValue);
const toggle = useCallback(() => setValue((value) => !value), []);
return [value, toggle];
};
The difference in your code and the article is that article has this code:
React.useCallback(()
Notice (). It doesn't take any parameter. So even when onClick passes the event it is being ignored in the article code.
But in your code you are using like this:
useCallback((defaultValue)
Here defaultValue becomes event object and that's why you see status: [object Object] in your output when you click on toggle button because event object is being converted to string in this call:
status: {open.toString()}
Hope this clarifies!
Maybe I don't understand what you're trying to achieve but something like this would toggle between true/false along with being much more simple?
const [toggle, setToggle] = useState(false);
const toggleButtonHandler = () => {
setToggle(!toggle);
};
return (
<div className="App">
<p>Status: {toggle.toString()}</p>
<button onClick={setToggle(false)}>false</button>
<button onClick={toggleButtonHandler}>toggle</button>
</div>
);

Click onClick twice in <Link> to update state

I'm trying to update my state by triggering the onClick event in my <Link>, but only after I click it twice then the output appears in my console, I have tried reading other question similar to this in stackoverflow but still could not find the solution, can anybody tell me what I did worng? Your help would be really great
import React,{useState} from 'react';
import { BrowserRouter as Router, Link } from 'react-router-dom';
const [search, setSearch] = useState("");
const [keyword, setKeyword] = useState("");
const handleChange = (e) =>{
setSearch(e.target.value);
console.log(search);
};
const handleClick = () => {
setKeyword(search);
setSearch('');
console.log(keyword);
};
return(
<div>
<input onChange={handleChange} value={search} placeholder="Search songs, artist, albums"/>
<Link onClick = {handleClick} to={`/songlist/${keyword}`}>Search</Link>
</div>
)
The thing you need to understand is : When you click, you add an event, and it's event is linked on your component and your props.
So you need to preventDefault to tell your event/props/component to act normally. Keep your actually code, but add e.preventDefault() at the begin of each event :)
Example :
const handleChange = (e) =>{
e.preventDefault();
setSearch(e.target.value);
console.log(search);
};
JS is async, so you need to handle effects using useEffect hook.
e.g. :
const [search, setSearch] = useState(null);
const [keyword, setKeyword] = useState(null);
const handleClick = () => {
setKeyword(search);
//setSearch('');
//console.log(keyword);
};
React.useEffect(()=>{
if (keyword) {
console.log(keyword);
setSearch(null);
}
},[keyword]);
can you try this, change
<Link onClick = {handleClick} to={`/songlist/${keyword}`}>Search</Link>
to
<Link to={`/songlist/${search}`}>Search</Link>

why didnt appear console

My question is related with react hooks. I'm doing api project for cars brand and model. As the first step when i selected from select element, thats will be install second select whats related with my first selected element. But i have a problem. when i select first step thats no appear console but when i second select console is appear my first select
function Home() {
const [api, setApi] = useState({});
const [userId, setUserId] = useState({});
const [errors, setErrors] = useState(true);
const [error, setError] = useState(false);
const id = useDispatch((userId)=>modelAction(userId));
let key;
let history = useHistory();
function handleClick(e){
key = api.filter(item => item.var_title === e.target.value);
setUserId({...key});
console.log(userId);
id({
type: 'MODELS',
id: userId
})
history.push('/model')
}
useEffect(()=>{
axios.get('https://api.carecusoft.com/tr/v1/chiptuning?key=testSA65D46ASD4AS8F4AS6F4A68')
.then(res=> setApi(res.data))
.catch(err => setErrors(true));
console.log(api);
},[userId]);
return (
<div>
<select onChange={e=>handleClick(e)} as={Link} to='/model'>
<option>Marka seƧ</option>
{
Object.values(api).map(item => {
const {id, var_title} = item;
return(
<option key={id} value={var_title} >{var_title}</option>
)
})
}
</select>
</div>
);
}
export default Home;
Your console log doesn't need to be in the useEffect.
Since it's not a side effect.
Have the console log outside above your return
Because you log your data inside handleClick function where you userid set. You need to log your data in your useEffect to see changes.
If you set your variables inside your Render with hooks in a
functional component changes in your variable appears with it's new value
in useEffect because you give the variable as a parameter to useEffect.
Like this example;
useEffect(()=>{
console.log('userId', userId);
},[userId]);
means, useEffect only triggered when userid changes.
Try this and you can see clearly what i mean,
useEffect(()=>{
axios.get('https://api.carecusoft.com/tr/v1/chiptuning?key=testSA65D46ASD4AS8F4AS6F4A68').then(res=> setApi(res.data))
.catch(err => setErrors(true));
console.log('api', api);
console.log('userId', userId);
id({
type: 'MODELS',
id: userId
})
},[userId]);
Hope it helps.

Categories

Resources