React componentDidMount not called on component reload - javascript

I have a list of data table. In data table I have data w.r.t to some device Whenever I click ID I open a sidebar with some data displaying inside that.
The problem what I am facing is onclick of ID first time it calls the api gets the data and displays properly. But, after closing sidebar when I click again on ID it doesn't load anything (no calls for APIs).
I am not able to create code pen for that but below is my code.
My Code -
onCLick ID -
_onClickCompliance(deviceId);
const _onClickCompliance = deviceId => {
ReactDOM.render(
<ComplianceDetails deviceId={deviceId} />,
document.getElementById("ComplianceDetailsModalDiv")
);
};
Inside ComplianceDetails component - First time onClick it goes inside componentDidMount but on click again it's not. That's why I have componentDidUpdate for this. If I remove this componentDidUpdate, it always loads the old data in sidebar after onCLick of ID in table.
`getDetailsByDeviceID` this is called to get the data from API and sets value in state
My Code -
componentWillReceiveProps() {
this.setState({ sideBarShow: true });
}
componentDidMount = () => {
this.getDetailsByDeviceID();
};
componentDidUpdate(prevProps) {
if (this.props.deviceId !== prevProps.deviceId) {
this.getDetailsByDeviceID();
}
}
getDetailsByDeviceID code -
getDetailsByDeviceID = () => {
try {
this._getComplianceDetailsApi(); //apis
} catch (err) {
toast({
message: err,
flavor: "error",
options: { isHtml: true }
});
}
};
If I remove this it calls the page indefinitely.
if (this.props.deviceId !== prevProps.deviceId)
Do I have to call componentWillUnmount()? Please guide me.
Let me know If I am not clear. Thanks.

If you want your component to re-mount when deviceId change you can use the key prop on ComplianceDetails, like this :
<ComplianceDetails key={deviceId} deviceId={deviceId} />

Related

ANTD table Print using ReactToPrint component

I am trying to print ANTD table using ReactToPrint hook, everything seems to work fine, but I want to show some text on top of page before print.
means I want to show some text for header purpose, when I am setting the visibility of header component true, its not print on first click, it shows on 2nd click, but I want to show the header on first click and when I print or cancel, header should be hide.
Please help me, Please hit print button two time to see the result in the below link.
https://codesandbox.io/s/usestate-not-updating-data-when-passing-from-parent-functional-component-using-r-forked-xuhnl
Thanks in Advance
When the handlePrint function is called, the ref componentRef points to the previous version of the component. printHeaderVisible only becomes true at the time of the next render.
You can try to postpone the print call until the next render like this
const reactToPrintFunc = useReactToPrint({
content: () => componentRef.current,
onBeforeGetContent: () => setprintHeaderVisible(true),
onAfterPrint: () => setprintHeaderVisible(false)
});
const handlePrint = () => {
setTimeout(reactToPrintFunc, 0);
};
or do as advised in this issue
const handlePrint = useReactToPrint({
content: () => componentRef.current,
onBeforeGetContent: () => {
return new Promise((resolve) => {
setprintHeaderVisible(true);
resolve();
});
},
onAfterPrint: () => setprintHeaderVisible(false)
});

How to test if url is updated while keeping history.location.search with Jest

I have a react application where I want to test the folowing behaviour.
I have some search criteria in the url /?my_filter_value=%5B\"FR\"%5D, and I have a button, when I click the button, a modal shows up and the url is updated /some_modal_id?my_filter_value=%5B\"FR\"%5D.
The test scenario I have is: Given that I click the button > When the modal shows up > I expect the url to be updated accordingly ie. some_modal_id is added to the url while keeping the initial search criteria.
describe('Given I click on the button', () => {
act(() => {
buttonModale.find('#actualButton').at(1).props().onClick();
});
describe('When the modal shows up', () => {
const initialUrlWithSearchCriteria = "/?my_filter_value=%5B\"FR\"%5D";
const history = createMemoryHistory({
initialEntries: [initialUrlWithSearchCriteria],
initialIndex: 0,
});
//expect(history.location.search).toBe(initialUrlWithSearchCriteria );
act(() => {
mount(
<Router history={history}>
<MyModalComponent showModal={true}/>
</Router>
);
});
const expectedModalUrl = `/some_modal_id`;
test('I expect the url to be updated with the modal id and keep the applied search', () => {
expect(history.location.pathname).toBe(expectedModalUrl);
expect(history.location.search).toBe(initialUrlWithSearchCriteria);
});
});
});
The first expect clause test is passing, so the url is actually getting "some_modal_id" part, but the second expect clause is failing. It seems that history.location.search is always an empty string.
I have tried to test if history.location.search is actually taking the initial value I am giving it and it seems to be working and the commented out expect case was passing.
Any help or tip on this will be highly appreciated!

React useState isn't setting opposite boolean correctly

I have a simple button on page with onClick event, and then useState hook that is by default set to false. Then I have elements on page, when I click on them I wanna do an action, but only if the state of that useState hook is set to true, which is done by if condition, but for some reason it passes it, even though the state should be false. My code:
Initiating the hook:
const [ isEraser, setIsEraser ] = useState(false);
Setting state on button click:
<span
className="scroll"
onClick={() => {
setIsEraser((isEraser) => !isEraser);
}}
>
The condition:
console.log('Eraser is set to', isEraser);
if (isEraser == true) {
// Code
}
The output of the console.log:
no changing state (is default false) -> false
changing state to true -> true
changing state back to false and triggering that event in which the condition is -> false, true, false
Edit:
I can't pass full component code, because it's kinda big, and some parts of code are protect by client contract, but the condition is in onClick event:
$body.on('click', '.tvs-annotated-text, .tvs-annotate-element', function(
e
) {
console.log('Eraser is set to', isEraser);
if (isEraser === true) {
setIsAlert(1);
// Odstraníme vybranému elementu backround
this.style.backgroundColor = '';
this.classList.remove('tvs-annotated-text');
this.classList.remove('tvs-annotate-element');
}
});
pretty sure you just need to do setIsEraser(!isEraser)
You don't have to use a function to set state setIsEraser((isEraser) => !isEraser); → setIsEraser(!isEraser)
Allright, so the problem was that the onClick trigger was written in jQuery, after rewriting it to normal javascript it works now. Big thanks to you guys.
In the setIsEraser you need to pass the last state. you passed the initial state in it so every time you press the button it passes false as isEraser.
change the isEraser in setIsEraser function to something else like pre or previous, etc.
<span
className="scroll"
onClick={() => {
setIsEraser((pre) => !pre);
}}
>
In this way pre would be the last state not the initial state and your program will work just fine.

Vue JS Event bus data not working outside scope of event

I am using event bus to show alert on update data.so whenever user update the data i want to show an alert showing "Data is udpated" so for that i am using event bus
here is BlogEdit.vue Component where i am firing event
app.$router.push('/', () => {
vueBus.$emit('showAlertBox')
})
And In BlogList.vue I am listning for this event
data: function(){
return {
showalert: false,
}
},
vueBus.$on('showAlertBox',(data) => {
this.showalert = true;
console.log(this.showalert); //Returns True
})
console.log(this.showalert); //Returns False
But the result is unexpected as it change back to false.
Why this.showalert changed to false ? So that cause to not showing alert box.
Since i am new to vue js i read the documenatation and other solutions but i cant figure out where am i going wrong with this.

How to access ref element that being conditionally rendered in v-if - Vue

I have an element that being conditionally rendered with v-if="isLogged", if a user is logged in:
<div
v-if="isLogged"
class="chatBlock"
ref="chat"
></div>
I'm trying to get scroll height of the chat reference in a mounted () function - this.$refs.logged.scrollHeight, but it's not possible, because if a user is not logged in, then this div won't be rendered on a mounting stage, so even if a user logs in - it won't work, because mounted stage already passed.
Is it possible to track element appearance in a DOM using watch method?
UPDATE
Added watcher, as Steven suggested below in a mounted ():
this.$store.watch(
(state) => {
return this.$store.getters.isLogged
},
(newValue, oldValue) => {
if (newValue) {
this.chatHeight = this.$refs.chat.scrollHeight
}
}
)
The accepted answer did not work for me. The watch does not guarantee that the element has already been rendered.
To make sure that the element is available, I had to use $nextTick
if (newValue) {
this.$nextTick(function () {
this.chatHeight = this.$refs.chat.scrollHeight
})
}
This will cause the code to be executed after the next DOM update cycle.
Add a watch to isLogged. When it is active, get your chat ref. You will also have to check on your mounted, so put your logic in a common function.
So in your component:
val componentOptions = {
methods: {
checkDiv() {
const chatDiv = this.$refs.chat
if (chatDiv) {
// your code here...
}
}
},
mounted() {
this.checkDiv();
},
watch: {
isLogged(value) {
if (value) {
this.checkDiv()
}
}
}
}
—-
You can also use v-show instead of v-if. That way your element will be rendered but hidden.
Switching to v-show, as suggested by Steven, worked for me. It was actually the better option because v-show is cheap to toggle, unlike v-if, see this answer: https://stackoverflow.com/a/44296275/2544357

Categories