React.useEffect(
() => {
const users = [
{id:123123123,
name:"mert",
del: <deleteButton onClick={()=>console.log(users)} />
}]
setusers(users)
}, [])
hello i have a problem
I created a useState called [users, setusers]
and in useeffect, I have assigned a delete function for each user.
this delete function needs to reach users state
But the problem starts here. When I want to reach users through the delete function,
I get the initial state of the state, (the state at the time I created the first user object)
In your useEffect hook you define a const variable called users.
In the onClick Event you output the const variable users and not the state variable users.
Which means const users is not equal to state.users
Rename your const variable 'users' and see if anything changes.
Related
I have been using these two ways interchangeably however I am not sure which one is the more correct. their behavior seems to be the same but I am sure there is a use case for each. Anyone can help me understand what's the proper use for each case?
const [customer, setCustomers] = useState(props.location.state);
useEffect(() => {
setCustomers(props.location.state);
}, []);
You should normally stick to the first one. Calling the setter of useState may lead to undesired re-renders and decreased performance.
In the first block the customer is initialised directly and no re-render happens. The setCustomer method will change the state and rerender the component. In the end the whole function will run twice which you can verify with a console.log.
const [customer, setCustomers] = useState(0);
useEffect(() => {
setCustomers(15);
}, []);
console.log(customer) // will first output 0 and then 15
Assuming in the second case, you have this as your useState statement:
const [customer, setCustomers] = useState();
The second one sets the value of customer on componentDidMount. So in the initial render, you will not have the appropriate value in your customer variable.
But yes, very soon after that the correct value will be set because of the code written in useEffect.
To clear it up, there will be 2 renders here (because the state variable value changes). In the first one, that won't be the case since the state variable has only one value from beginning.
The first one is more effective.
const [customer, setCustomers] = useState(props.location.state);
If you use second one (by using useEffect), your component will be re-rendered again.
That's, your state variable customer will be updated in useEffect after DOM is initially rendered, this leads the 2nd re-render of the component.
But if you want customer to be updated by props.location.state, you need to add useEffect hook like the following.
useEffect(()=> {
setCustomers(props.location.state);
}, [props.location.state]);
Setting the state's default value upon declaring it is probably the more correct way to go, since it does not trigger a re-render.
Every time you call a setState your component will be re-rendered, so when you do so in the useEffect, you will trigger an unnecessary re-render upon the component mounting, which could be avoided by doing the good ol'
const [value, setValue] = useState(props.location.state)
While of course there are exceptions and many different use cases, setting an initial state in a useEffect is more useful, for example, when you have values you'd expect to change regardless of your component (for example from an external asynchronous API call):
const [value, setValue] = useState(valueExpectedToChange)
useEffect(() => {
setValue(valueExpectedToChange) // will trigger the rerender only when valueExpectedToChange changes
}, [valueExpectedToChange])
I am trying to build an ecommerce website, and I hit a problem I cannot seem to resolve. I am very new to react and JS so have some patience please :)
I declared 4 useStates in my app.js:
const [elementeDinState, setElementeDinState] = useState([]);
const [currentCategorie, setCurrentCategorie] = useState("Acasa");
const [subCategorie, setSubcategorie] = useState([]);
const [cartContents, setCartContents] = useState([]);
const fetchData = useCallback(async () => {
const data = await getCategories();
setElementeDinState(data);
}, []);
useEffect(() => {
fetchData().catch(console.error);
}, [fetchData]);
const changeHeader = (dataFromMenuItem) => {
setCurrentCategorie(dataFromMenuItem);
};
const changeCopiiContent = (data1FromThere) => {
setSubcategorie(data1FromThere);
};
const changeCart = (dataFromCart) => {
setCartContents(dataFromCart);
};
I am passing the functions to change those states to different child components as props. my problem is, when I add items to cart it triggers a re render of my component (products listing component) that should not be affected by cartContents and that resets the state of said component to the initial value that changes the items being shown. does useState hook create a single global state comprised of all those states?
If these useState are defined in the app.js and then passed down, when a child will use them chasing the state will happen in the app.js so all the children of <App /> will be re-rendered.
I guess that your app.js looks similar:
function App() {
const [elementeDinState, setElementeDinState] = useState([]);
// ...and the other hooks and methods
return (
<cartContents setElementDinState={setElementeDinState} />
<ProductList />
)
}
In this case the state is in the component so when <CartContents /> changes it, it will trigger a re-render of the and all its children <ProductList /> included.
To avoid this problem think better when each piece of state needs to be and put the state as near as possibile to that component. For example, if the state of the cart does not influence the Product list. Move the useState in the <Cart /> component.
From what I understand, your problem is that you're simply resetting the cartContents state every time you call the changeCart function, correct?
What you probably want, is to add (or remove ?) the item to the cart, like this?
const changeCart = (dataFromCart) => {
setCartContents(oldContents => [...oldContents, dataFromCart]);
};
Here is a description of useState from the oficial site:
useState is a Hook (...). We call it inside a function component to add some local state to it
So it creates just a local state.
About your problem, We need more information, but I believe that some parent component of that widget is trying to render other component instead of your the component that you wanted (let's call it "ProblemComponent") and rendering you ProblemComponent from scratch again, before you can see it.
it's something like that:
function ParentComponent(props: any) {
const isLoading = useState(false);
// Some logic...
if(isLoading) {
return <LoadingComponent/>;
}
return <ProblemComponent/>;
}
If that doesn't work you can also try to use React.memo() to prevent the ProblemComponent to update when it props change.
well, seems like I wanted to change the way react works so I figured out a work around, based on what you guys told me. I declared the state of the productsComponent in the parent component and adding to cart now doesn't force a refresh of the items being shown. thank you!
I have a array in React which is to be shown using useEffect. That thing got from the previous component to next component. Now, I am using useEffect to set the array on page load using useState. But when I refreshes the page, the array gets undefined and the page goes blank. How to get the array again, so that it never throws me error even if I reload the page.
I have used sessionStorage and localStorage. But nothing is working out for me.
This is the code I have done so far:
const location = useLocation();
useEffect(() => {
console.log(location.groupsname);
sessionStorage.setItem('groups', JSON.stringify(location.groupsname));
const a = JSON.parse(sessionStorage.getItem('groups'));
console.log(a);
setimportedgroups(a);
}, []);
How should I resolve that?. Thank you.
Issue
You are close. The issue here is that you are wiping out any saved storage value when the component mounts again.
useEffect(() => {
// setting storage is synchronous
sessionStorage.setItem('groups', JSON.stringify(location.groupsname));
// getting the value just set
const a = JSON.parse(sessionStorage.getItem('groups'));
console.log(a);
setimportedgroups(a);
}, []);
If, upon page reload, location.groupsname is undefined then this is what is stored and loaded back from storage.
Solution
You'll want to use a state initializer function and two useEffect hooks, 1 to persist to storage local state when it updates, and a second to update local state when the location groupsname updates and has a defined value.
const location = useLocation();
// initialize state from storage on mount
const [importedGroups, setImportedGroups] = useState(() => {
const groups = sessionStorage.getItem('groups');
return JSON.parse(groups) ?? {};
});
// persist importedGroups state to storage
useEffect(() => {
sessionStorage.setItem('groups', JSON.stringify(importedGroups));
}, [importedGroups]);
// update local state when location.groupsname updates
useEffect(() => {
if (location.groupsname) {
setImportedGroups(location.groupsname);
}
}, [location.groupsname]);
I have an array of certain objects in my redux store and I retrieve it like so:
const storeExpenses = useSelector(({ expenses }: RootState) => expenses.items));
I then save those expense objects also in the components local state since I have to further filter them without wanting to change them in the store.
const [expenses, setExpensesInState] = useState<Expense[]>(storeExpenses);
Now, when my store expenses are updated somewhere else, I want to refresh the local state as well, like so:
useEffect(() => {
setExpensesInState(storeExpenses));
}, [storeExpenses]);
However this results in an endless loop of the useEffect hook.
My assumption is that when I use setExpensesInState, I trigger a redraw of the component which then sets the expensesInStore variable which in turn triggers again the useEffect and so on. Is this assumption correct or am I misunderstanding anything else? And how would I resolve this to achieve what I need?
I'm having an odd issue where some times the value passed into useState is not the same as the variable for useState. This happens on the same UI component each time while others are not having the issue. Just wanted to double check if I'm doing anything wrong here.
// userData is from Redux store
const {userData} = props
const [installed, setInstalled] = useState(userData.installed) // installed: boolean
console.log(userData.installed) // returns true
console.log(installed) // returns false
console.log(userData) // installed: true
Reason I'm using useState is because I'm using it to render a button that will be toggled, as well as displaying an indicator whether it is toggled or not.
<Button onClick={() => setInstalled(!installed) />
I recommend to use useEffect to watch the state inside your Redux store then update the local state based on that changes :
const [userData] = props ;
const [installed, setInstalled] = useState(userData.installed)
useEffect(() => {
setInstalled(userData.installed)
},[userData])