Not able to _.debounce and change the state in react.js - node.js

I'm trying to use lodash's debounce method to to toggle a boolean located in the state 500ms after the scroll occured.
I've look for responses on SO but none of these helped me to fix this. This seems fairly simple so there's probably something that I didn't get.
The state is:
constructor(props) {
super(props);
this.state = {
isScrolling: false
}
}
The componentDidMount part is:
componentDidMount(){
window.addEventListener('scroll', this.handleScroll, true);
window.addEventListener('scroll', _.debounce(() => {
this.setState({
isScrolling: false
})
}, 500))
}
The scroll function is:
handleScroll = (event) => {
this.setState({
isScrolling: true
})
};
In my rect chrome dev. tools, I see that isScrolling is toggling to true when I start scrolling but the debounce method does not toggle it back to false again. What am I doing wrong?

EDIT - My code was correct but this bit of css code was preventing the correct behavior to happen:
html, body {
height:100%;
}

Related

wrapper emitted() not working in vue test utils composition api

I am trying to make a simple test to check that the button is emitting an event called "click" every time it is detected, the problem is that when I use wrapper.emitted('click') to validate that it is receiving it, it always arrives as an empty object... I don't know what I may be doing wrong.
Current versions:
Vue: 3.2.31
Vitest: 0.7.12
Vite: 2.8.6
Vue/test-utils: 2.0.0-rc.17
<template>
<button
class="eci-button"
:disabled="props.disabled"
#click="handleClick"
>
{{ props.label }}
</button>
</template>
<script setup lang="ts">
/* Interfaces and types */
interface Props {
label: string
disabled?: boolean
}
/* Props */
const props = withDefaults(defineProps<Props>(), {
disabled: false
})
/* Events */
const emit =
defineEmits<{ (e: 'click'): void }>()
/* Methods */
const handleClick = () => {
emit('click')
}
</script>
<style lang="scss" src="./Button.scss"></style>
Test
test('should render and emit event at click', async () => {
const label = 'Siguiente'
const wrapper = mount(Button, {
props: {
label
}
})
wrapper.trigger('click')
expect(wrapper.emitted()).toHaveProperty('click')
})
Result
OK, I found the problem... I am using happy-dom as test environment together with Vitest... the problem is that when you pass a property as "optional" for some reason it interprets it as if it was "true"... to explain myself...
I have a default prop "disabled" set to "false" which means that my button should print as:
in the DOM.. but, for some reason it interprets it as being true and that causes the "click" events not being executed.. i will keep looking for some fix for this, at the moment i have migrated for jsdom and solved.

Jest Test on Stencil Component does not apply changes in variables

I want to test a stencil component and configure a global variable in my test like this:
describe('my-component', () => {
const myVarMock = 1;
let page;
let shadowRoot: ShadowRoot;
beforeEach(async () => {
page = await newSpecPage({
components: [MyComponent],
html: `<my-component></my-component>`,
supportsShadowDom: true,
autoApplyChanges: true
});
shadowRoot = page.root.shadowRoot;
});
it('should test', () => {
page.rootInstance.myVar= myVarMock;
page.rootInstance.componentWillLoad();
page.rootInstance.render();
console.log(shadowRoot.innerHTML.toString());
const buttonElement = shadowRoot.querySelector('.my-button'); //is null because shadow root is empty
});
});
My Component only renders something, when myVar is set. In the console.log of my test, shadowRoot is always empty, although I explicitly call render() in the test and when I go through the render function in debug-mode it has a value for myVar and renders everything. But why is shadowRoot then empty and my buttonElement is undefined?
Component:
#Component({
tag: 'my-component',
shadow: true,
})
export class MyComponent{
public myVar;
componentWillLoad() {
...
}
render() {
return (
<Host>
{this.myVar? (
<div class="my-button"></div>
): null}
</Host>
)
}
}
Calling those life-cycle hooks like componentWillLoad and render manually does not do what I think you're expecting it to do. The Stencil runtime calls render and uses the return value (JSX) to eventually render your component. Manually calling render does not render or re-render your component. In fact, it doesn't do anything except returning some JSX to you but you're not doing anything with the return value.
I think the main issue in your case is that myVar is not declared as a property with the #Prop() decorator. So even though you have marked your class member as public and are able to change it from the outside, Stencil will not wire up anything for you regarding that prop. See https://stenciljs.com/docs/properties.
Instead, you'll have to define it as:
#Prop() myVar?: number;
That way it will cause Stencil to re-render your component every time you update the prop's value.
Your test case should just look like
it('should test', () => {
page.root.myVar = myVarMock;
console.log(shadowRoot.innerHTML.toString());
const buttonElement = shadowRoot.querySelector('.my-button');
expect(buttonElement).not.toBeNull();
});

Trigger a function from father component - that will run componentDidMount at child's component

so i got this React project - there is an admin page and i can add new vacations (with Reactstrap Modal).
the Vacations are added to the database and are shwon in a child's component called AdminVacations.
the array of the Vacations is loaded at the child's component.
this is the code to add Vacation (in admin component)
async Add (){
let NewVac = {
name:this.state.name,
price:this.state.price,
start:this.state.start,
end:this.state.end,
image:this.state.file,
description:this.state.description
}
let r = await fetch(`${apiUrl}/addvacation`, {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify(NewVac)
});
let jsonData= await r.json();
if (r.status === 200){
this.toggle();
}
}
i also got edit and delete buttons - which found in the child's child component.
the problem is that i need to show the changes on the screen(Live).
i manage to do it with the edit and delete button (because they are found in the same component)
but the add button is not there.
how can i make the Vacations state be reloaded again in the child's component from his father component?
import React, { Component } from 'react';
import apiUrl from './apiUrl';
import AdminVacation from './AdminVacation';
import AdminNavbar from './AdminNavbar'
class AdminVacations extends Component {
state={
Vacations:[],
userid:''
}
render() {
return (
<div className="container">
<div class="row">
{this.state.Vacations.map(data=> <AdminVacation key={data.id} data={data} RefreshFunc={this.RefreshFunc.bind(this)} />)}
</div>
</div>
)
}
async componentDidMount(){
let response = await fetch(`${apiUrl}/allvacations`);
let data = await response.json();
this.setState({ Vacations:data })
}
RefreshFunc(){
console.log("something Happened")
this.componentDidMount()
}
}
export default AdminVacations;
(basically i want to run componentDidMount in the Child's component (from Admin) again every time i add a Vacation - and not just when i edit it or delte it.
the Edit and Delete are found in AdminVacation Component.
You can use the componentDidUpdate lifecycle method in the child to check for any updates to the props. In a nutshell, it works like this. The following code checks if the current props and previous props, with respect to location are different, and if so, it performs the actions inside the if block.
componentDidUpdate(prevProps) {
if (this.props.location !== prevProps.location) {
window.scrollTo(0, 0); // reset scroll on route change
}
}

How to know the sideMenu visibility state

I have a topBar with a button that toggles the Side Menu.
I have registered a navigationButtonPressed action as below
navigationButtonPressed({ buttonId }) {
switch (buttonId) {
case 'sideMenuButtonId':
Navigation.mergeOptions(this.props.componentId, {
sideMenu: {
left: {
visible: true
}
}
});
break
default:
break
}
}
But in this case, the button only makes the sideMenu visible, and Im trying to use it so it toggles the menu open and closed.
So i replaced the above with a variable approach seen below..
var sideMenuVisible = false
navigationButtonPressed({ buttonId }) {
switch (buttonId) {
case 'sideMenuButtonId':
sideMenuVisible = !sideMenuVisible
Navigation.mergeOptions(this.props.componentId, {
sideMenu: {
left: {
visible: sideMenuVisible
}
}
});
break
default:
break
}
}
Which works fine if the user only uses the button to open and closed the sideMenu, but the user can also open/close the menu by swiping to open the menu as well as tapping out the menu to close it.
Is there a way to check the visibility of the sideMenu so I can properly use an action to open/close the menu on command?
It can done much more simple.
Think you should create it as a state, because the component have to know, it should be rerendered, when the state change.
So something like
state = { isOpen: false };
toggleSidebar = () => {
this.setState({ isOpen: !isOpen })
}
And now, you should call the toggleSidebar function when you click the button

React native props,ref value is undefined inside keyboard hide event?

i am trying to clear my Textinput focus inside keyboard hide event,but i am not able to get reference
inside keyboard hide event method.i tried to print props value it also getting undefined
constructor (props) {
this.inputs = {};
}
_keyboardDidHide () {
console.log("value"+this.props);
this.inputs['inputValue'].blur();
}
componentWillMount () {
this.keyboardDidHideListener = Keyboard.addListener('keyboardDidHide', this._keyboardDidHide);
}
componentWillUnmount () {
this.keyboardDidHideListener.remove();
}
<TextInput
ref={input => {
this.inputs['inputValue'] = input;
}}
autoFocus={true}
blurOnSubmit={false}
/>
let me know how to clear the TextInput focus on _keyboardDidHide method.
I'm not 100% sure what you're trying to do here, however I assume you want to at least get the info out from your input.
No need for that ref magic there though, just use simple react state changes.
class InputWrapper extends React.Component {
constructor() {
super();
this.state = {
input: ''
};
this.handleInput = this.handleInput.bind(this);
}
handleInput(input) {
this.setState({input});
}
render() {
return (
<TextInput onChangeText={this.handleInput} />
);
}
}
This will give you a TextInput Component with control over the input.
Now you should add a componentDidUpdate method as well, that prints out the current state, so you can observe what is happening when you change the input value.
componentDidUpdate() {
console.log(this.state);
}
As for bluring and such, you should definitely check out the documentation on TextInput : https://facebook.github.io/react-native/docs/textinput.html
Additionally, might I suggest to jump into the lifecycle documentation of react itself, plus checking up on props vs state in react. It is a confusing concept in the beginning and you should definitely revisit it.
As for blurring the input, simply do this:
<TextInput
ref={input => this.input = input}
/>
And then you can call:
this.input.blur();
wherever you want.
Also, do not forget to bind your _keyboardDidHide callback within your constructor or when adding it as the listener callback, like so
this._keyboardDidHide = this._keyboardDidHide.bind(this)
Keyboard.addListener('keyboardDidHide', this._keyboardDidHide.bind(this));
Hope this helps

Resources