Why is useState not triggering re-render?
You're calling setNumbers
and passing it the array it already has. You've changed one of its values but it's still the same array, and I suspect React doesn't see any reason to re-render because state hasn't changed; the new array is the old array.
One easy way to avoid this is by spreading the array into a new array:
setNumbers([...old])
react useState not re rendering
Your useEffect
is not being told to update. useEffect
needs to be passed the value/dependencies that it needs to (trigger the) update on. Without it, the effect will only run once on (initial) component render
const [tagsWithData, setTagsWithData] = useState([]);
useEffect(() => {
....
const finalsTags = temp.map((item) => item.name);
setTagsWithData(finalsTags);
}, [temp]); // <--- add this
Below is a small example illustrating the differences. Click on the button, and check out the output of both effectWithDep
and effectWithoutDep
. You'll notice only effectWithDep
will update.// Get a hook function
const { useState, useEffect } = React;
const Example = ({title}) => {
const [count, setCount] = useState(0);
const [effectWithDep, setEffectWithDep] = useState(0);
const [effectWithoutDep, setEffectWithoutDep] = useState(0);
useEffect(() => {
setEffectWithDep(count)
}, [count])
useEffect(() => {
setEffectWithoutDep(count)
}, [])
return (
<div>
<p>{title}</p>
<p>effectWithDep: {effectWithDep}</p>
<p>effectWithoutDep: {effectWithoutDep}</p>
<button onClick={() => setCount(count + 1)}>
Click me
</button>
</div>
);
};
// Render it
ReactDOM.render(
<Example title="Example using Hooks:" />,
document.getElementById("react")
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.1/umd/react-dom.production.min.js"></script>
<div id="react"></div>
React useState is not re-rendering while it is referring cloned array by spreading
Sometimes I facing this issue too, in my case I just "force" render calling callback.
First solution:
const [reviews, setReviews] = useState([...book.reviews]);
useEffect(() => {
const sortedReviews = [...reviews]
.sort((review1: IReview, review2: IReview) =>
sortBy(review1, review2, sortRule));
setReviews(()=> [...sortedReviews]) // <-- Here
}, [sortRule])
second solution:You can use useRef to get data in real time, see below:
const [reviews, setReviews] = useState([...book.reviews]);
const reviewsRef = useRef();
useEffect(() => {
const sortedReviews = [...reviews]
.sort((review1: IReview, review2: IReview) =>
sortBy(review1, review2, sortRule));
setReviewRef([...sortedReviews])
}, [sortRule])
function setReviewRef(data){
setReview(data);
reviewsRef.current = data;
}
So, instead use the state reviews use reviewsRef.current as u arrayI hope you can solve this!
useState not re-rendering component if it is called inside callback function
Update it with useRef,
The reason why useState doesnt show the latest value is because useState is asynchronous. So in your case useState is being updated without giving it a chance to re-render. In these cases useRef plays a better role.
import React, {useRef} from "react";
const Upload = () => {
const percent = useRef(0);
const progListener = (event) => {
percent.current = Math.round((event.loaded * 100) / event.total)
}
return (
<h6>{percent.current}</h6>
<Dropzone onDropAccepted={dropAccepted}/>
)
}
Why does React useState hook trigger a re-render before remaining code executed?
Doesn't setCount result in the scheduling of a re-render that is not immediate? Shouldn't the console log immediately after the setCount function call always execute before the re-render is triggered?Under the hood, React optimizes re-renders by queuing and batching them when it can determine that it's safe to do so. When in a function React understands (such as a functional component, or a hook callback), if you call a state setter in one of those functions, React will know that it's safe to delay the state update until its processing is finished - for example, until all effect / memo / etc callbacks have run, and until all components from the original state have been painted onto the screen.
But when you call a state update outside of a built-in React function, React doesn't know enough about its behavior to know when it'll be able to re-render next if it delays the state update. The setTimeout
call is not called from inside the React lifecycle, so batching updates and optimizing them is much more difficult - so, rather than React trying to guess how it could be done safely and asynchronously, it re-renders immediately.
Mocked useState not triggering a rerender React Testing Library
Why is the component not re-rendering when the value being returned by the useContext
has been updated?
You mock React.useContext
, its mock implementation breaks the real useContext
feature. This means React doesn't know how to detect the context changes because you replace useContext
with your mock.Is there just a better way to achieve this. I feel like I might be going all around the world to do something that is probably simpleDon't mock anything provided by React, incorrect mock will break the feature of React. If your test case is built on these incorrect mocks, your test cases may pass but your code may be wrong in runtime. For more info, see What you should avoid with Testing Library
Render the context provider and component as usual, use RTL queries to find the target element, and fire an event on it. Then check what has been rendered of the component.
E.g.
TestContext.tsx
:
import React, { createContext, Dispatch, SetStateAction, useState } from 'react';
export const TestContext = createContext<{
stateVariable: number;
setStateVariable: Dispatch<SetStateAction<number>>;
}>(null!);
export default function TestContextProvider({ children }) {
const [stateVariable, setStateVariable] = useState(1);
return <TestContext.Provider value={{ stateVariable, setStateVariable }}>{children}</TestContext.Provider>;
}
Component.tsx
:import React from 'react';
import { useContext } from 'react';
import { TestContext } from './TestContext';
export default function ComponentToBeTested() {
const { stateVariable, setStateVariable } = useContext(TestContext)
return (
<>
<h1>
Current value: <span data-testid="answer">{stateVariable}</span>
</h1>
<button data-testid="increment-button" onClick={() => setStateVariable(stateVariable + 1)}>
Increment
</button>
</>
);
}
Component.test.tsx
:import React from 'react';
import { fireEvent, render, screen } from '@testing-library/react';
import '@testing-library/jest-dom/extend-expect';
import ComponentToBeTested from './Component';
import TestContextProvider from './TestContext';
describe('73039704', () => {
test('should pass', () => {
render(
<TestContextProvider>
<ComponentToBeTested />
</TestContextProvider>
);
expect(screen.getByTestId('answer')).toHaveTextContent('1');
const button = screen.getByTestId('increment-button');
fireEvent.click(button);
expect(screen.getByTestId('answer')).toHaveTextContent('2');
});
});
Test result: PASS stackoverflow/73039704/Component.test.tsx (11.423 s)
73039704
✓ should pass (33 ms)
-----------------|---------|----------|---------|---------|-------------------
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
-----------------|---------|----------|---------|---------|-------------------
All files | 100 | 100 | 100 | 100 |
Component.tsx | 100 | 100 | 100 | 100 |
TestContext.tsx | 100 | 100 | 100 | 100 |
-----------------|---------|----------|---------|---------|-------------------
Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 total
Time: 12.116 s
React not triggering re-render with useState hook
Ok, I fixed this by updating the object through the cloneAndUpdate
(Hooks API Reference) method instead of afterwards
assign[personInfoTypeId] = {$push:[newEmptyRow]};
let newPersonInfoTypeFieldsState = cloneAndUpdate(formValuesById,assign);
setFormValues(newFormValuesState);
I think the library isn't actually doing a deep copy but re-using parts of the structure that haven't changed so I suspect trying to manually update this afterwards was actually updating the original reference that react new about and thus react recognised no difference when setting state. Using the correct $push
syntax documented in the library fixed it. After changing UseState Hook React component not re-rendering
In useToken.js
const saveToken = userToken => {
localStorage.setItem('token', JSON.stringify(userToken));
setToken(userToken.token);
}
should be replaced to const saveToken = userToken => {
localStorage.setItem('token', JSON.stringify(userToken));
setToken(userToken); //userToken.token changed to userToken
}
Because, there is no variable named as 'token' in userToken object. It is token itself. So the hook thinks that there is no change and because of that it does not re-render. Initial values in useState not updated after re-render
The selectedTags
state in the useState
hook is only initialized once.
If tags
remains a truthy defined array (even empty arrays are truthy and defined) then the EditTagsModal
component remains mounted by {tags && <EditTagsModal existingTags={tags} />}
. If the tags
value, and thus the existingTags
prop updates and EditTagsModal
is rerendered, then you should implement an useEffect
hook with a dependency on the existingTags
prop to update the local state when the prop value updates.
useEffect(() => {
setSelectedTags(existingTags);
}, [existingTags]);
useEffect
with a dependency array is synonymous to a class component's componentDidMount
and componentDidUpdate
lifecycle methods.
Related Topics
Javascript: Unicode String to Hex
JavaScript Ternary Operator Example with Functions
If (Key in Object) or If(Object.Hasownproperty(Key)
Keep Bootstrap Dropdown Open When Clicked Off
Catching Errors in JavaScript Promises with a First Level Try ... Catch
Jquery: Change Event to Input File on Ie
Passing a PHP Variable to JavaScript in a Blade Template
How to Bind to the Change Event of a Textarea in Jquery
C# Web Method Is Not Calling in JavaScript
How to Parseint a String with Leading 0
JavaScript Get Object Key Name
Why Use Redux Over Facebook Flux
How to Send Email by Using JavaScript or Jquery
Finding "Line-Breaks" in Textarea That Is Word-Wrapping Arabic Text
Regular Expression for Url Validation (In JavaScript)