This question already has answers here:
Why React needs another render to bail out state updates?
(2 answers)
Does react re-render the component if it receives the same value in state
(2 answers)
React hooks call setState with same primitive value still cause re-render
(2 answers)
Closed last month.
I had thought once we call the trigger function then the page will re-render no matter what value we pass in but I found that if we pass a value same as the current value then it won't re-render.
But it's still weird when I tried this code below:
const Last = ()=>{
const [fruit,eat] = useState('Apple')
console.log('Current fruit is '+fruit)
return(
<div>
<h1>{fruit}</h1>
<button type='button' onClick={()=>eat('Banana')}>Try me</button>
</div>
)}
When the page first loaded, we passed 'Apple' into useState and hold by variable fruit, then we got 'Current fruit is Apple in the console'. Next I clicked the button and triggered the function 'eat' and passed 'Banana' into it, then we got page re-rendered and message 'Current fruit is Banana' in the console. Weirdly when I clicked the button again the function 'eat' got called and the page got re-rendered again. It shouldn't be as I pass a value 'Banana' same as current value hold by fruit. But when the third time I clicked the button, the page didn't re-render anymore. It's:
Page first load --> 'Current fruit is Apple' in console
first time click button --> 'Current fruit is Banana' in console
second time click button --> 'Current fruit is Banana' in console
third time click button --> No message in console
Now I am so confused with the mechanism of useState. Can someone tell me in which step I got wrong, really appreciate it.
I have read the React documentation about useState and the rule of hooks
Related
we use ag-grid version 20.2.0.
I am doing something like
``https://plnkr.co/edit/?open=main.js&preview.
I get data from API. Data is an array of objects and object has many values and Boolean value.
This values will be displayed in grid which is react component and button which is also a react component whose display is based on Boolean value.
All works fine until new data comes. New data has only value change which should be changed in only one cell and the button in that row based on Boolean value should be hidden or displayed.
I was able to achieve this but I get warning "unstable_flushDiscreteUpdates: Cannot flush updates when React is already rendering."
After doing some research I found this solutions
https://github.com/ag-grid/ag-grid/issues/3680
According, to this I need to use deltaRowDataMode={true} and getRowNodeId={(data) => data.id} in grid options. Now the warning is gone.
But the Boolean change is not reflecting, only value change is reflecting and cell value is changed and as Boolean value is not recognized the button is not hidden.
In the data when it comes to ag-grid I can see both value and Boolean value changes. But the part where I check Boolean and display or hide button is not getting triggered.
In above github there is also demo which shows the issue still exists.
`` https://codesandbox.io/s/ag-grid-formik-fieldarray-integration-cjcie
Can somebody let me know if I can do any other way updating only one cell value in ag-grid and hiding button without the above warning?
Or is there something else I need to add with deltaRowDataMode?
I have a react app similar to what is shown in this codesandbox link
https://codesandbox.io/s/eatery-forked-t44bx?fontsize=14&hidenavigation=1&theme=dark
Clicking the Menu at the bottom center of the page renders the MenuFilter component.
The way I have it now, checking the checkbox immediately updates the checked items. This is good from a user interface point of you.
User gets instant feedback on what he is clicking on (what is getting un-clicked if something is getting un-clicked).
The problem with though is that the OK/Cancel button loose there use. In other words, after making changes to the selection, if the user decides that we does not want any of these new selection & rather revert back to old selection (the one before the Menu button was clicked), he cannot do that because all the states have been updated (updating happens as the check boxes are being clicked).
How to update the state ONLY if OK (currently only CANCLE button is working, so you can consider that) button is clicked. However, the check-marks should none the less change as the user is clicking them.
Is there a way to do this other than creating a 'temporary' state (I don't want to do this) to update the visual changes & only when a button is clicked, the changes are done one the data.
You can change the checkedItems to a local state of the MenuFilter component, and pass it as an argument on onClick. That way, when you open the modal, the component mounts again and the state should return to its default.
Something like:
export const MenuFilter = ({ onClick, onCheck }) => {
const [checkedItems, setCheckedItems] = useState(["allItems"])
return (
<button onClick={() => onClick(checkedItems)}>Cancel</button>
)
}
Edit: You'll still need some sort of state to handle the data on the parent component, but you won't have to manually handle resetting the data.
I have a react app similar to what is shown in this codesandbox link https://codesandbox.io/s/eatery-v1691
Clicking the Menu at the bottom center of the page renders the MenuFilter component.
The MenuFilter component in turn uses a checkbox component to render several check boxes & the checked status of these checkboxes depends on the selectedMeals prop that I pass to the MenuFilter in app.tsx.
I read that when the state is passed as a prop, the re-rendering happens as soon as the state changes but this is not happening.
The selectedMeals state is initialized with allItems and then managed such that when any other items is click, that items is set & allItems and these individual items can be several at once. The state management works fine but the checkbox is not getting updated based on the state!
If you however, click cancel (ok button does not do anything yet) & then click Menu button again, only the values in the selectedMeals prop are rendered.
See the video here (https://youtu.be/Zmfc0MQGaIU this is the full app, codesandbox app is representation of this but not the same) where the state change (allItems gets removed & when allItems is checked other items get removed) works perfectly but the check boxes are not re-rendering appropriately
What am I doing wrong & more importantly how do I get the result I want?
I initially put the question here re-render as soon as the state is changed but there was no sandbox for it & since the sandbox is different from what I put in that question, I created a new question. Thanks.
In this video https://youtu.be/2v3lOPaIPzU I have captured the change in the selectedMeals in console log & I also show how the checkboxes does not match the selectedMeals.
The problem is in the Checkbox component.
const [checked, setChecked] = useState(isChecked);
isChecked will only be used as the initial value, checked will not update every time isChecked changes. You could manually update checked in a useEffect hook with isChecked as a dependency, but it is unnecessary as the Checkbox component can be implemented without any state.
If you however, click cancel (ok button does not do anything yet) &
then click Menu button again, only the values in the selectedMeals
prop are rendered.
That's because the modal is conditionally rendered based on menuModalIsShown and when this boolean gets toggled, the component unmounts and mounts back causing useState(isChecked) to use the updated state.
Updated Checkbox:
export const CheckBox = ({
standAlone,
text,
onCheck,
isChecked,
value
}:
CheckBoxProps) => {
return (
<div
className={`${styles.checkbox} ${
standAlone ? "" : styles.notStandAlone
} `}
>
<input
type="checkbox"
checked={isChecked}
onChange={onCheck}
value={value}
/>
<label htmlFor={styles.checkbox}>{text}</label>
</div>
);
};
Background
So I build a front-end project for a delivery service, based on React and Material UI.
I was asked to use a Dialog window that will be opened when clicking on item, and there the user will have the opportunity to customize the item.
The dialog can be seen here(very simple: item photo, name, desc, and customization options):
https://ibb.co/GFkpy8Q
(Sorry for the pixelization)
The problem
I use react hooks in this project, and that why manage the Dialog's state.
Although simple, I stumbled upon few problems with how elements got re-rendered/not re-rendered(when expected):
The "checked" prop of the checkboxes uses Array.some, to see if the unique ID of the checkbox is in the state Array. The checkboxes are not being set to checked when clicking on them. The onChange prop simply pushes the checkbox's value to the state array and sets the state:
const [array, setArray] = React.useState([]);
...
<Checkbox
checked={
array.some(
item => item._id === subOption._id
)
}
onChange={() => setArray(array.push(subOption))}
/>
The onChange action works properly, so why the "checked" prop doesn't work properly?
When a checkbox is checked, I want to add a small quantity field next to it, so the user will be able to choose the quantity of the subOption he shall receive.
So I use the next well-practiced pattern:
{array.some(item => item._id === subOption._id) &&
(
<QuantityField />
)
}
The problem is that the QuantityField is not shown after the checkbox get checked.
If I exit the Dialog and enter it again, I suddenly see the checked checkbox is checked, and the QuantityField is shown next to it 😕
If I change the item's quantity with the general QuantityField you can see at the bottom left of the Dialog image, suddenly all the checked checkboxes gets unchecked 😕
The general QuantityField uses a state of it's own, and is not connected to any of the checkboxes.
From what I could see after I tried to debug the weird behavior, I can say that the render action of the Dialog component isn't working as expected. The states are updated, but doesn't trigger a re-render of the Dialog tree. Actually, it is wrong to say that, as the Dialog tree gets re-rendered, but the "checked" prop is not being re-checked during the re-render; but a complete un-mount and re-mount of the Dialog shakes the tree right.
Hope for an interesting answer. Thank you.
I would change how you are using setArray. See from Array.prototype.push() documentation:
The push() method adds one or more elements to the end of an array and returns the new length of the array.
Also using .push() on the state is not allowed because never should mutate the state directly.
Suggested solution instead:
onChange={() => setArray(prevState => [...prevState, subOption])}
I have angular component, which is loading other components , now in a event change say dropdown item selection, i need to reload just one specific component. Is it Possible to do that?
I looked into some answers in stack overflow itself but mostly are about reloading the whole page.
<dropdown (change)="detectChange($value)" />
<Component-one></Component-one>
In one component i have a 'drop down' with few values, and other component say 'component-one' already loaded with it , when the value in the "dropdown" changes i need to reload "component-one".
It is a general question. First of all you need to understand what you want to achieve in the end.
One way for "reloading" component, pass some data to the component based on the dropdown value, so, it will automatically "reload".
The other way is that you can have url param or query param based on the dropdown value, and on dropdown value change, navigate to the route with new param value, so the component will "reload".