What value to give void properties - javascript

I have this interface:
interface Props {
close: () => void;
disableButton: () => void;
showPrompt: boolean;
pol: string;
}
I'm trying to use it in a test. My problem is that I don't know what I should do with close and disableButton. They are just passed to that class so the state can be updated. What value do I give the variables for use in my shallow?
describe('<Reissue />', () => {
it('calls reissue service', () => {
const close = ???;
const disableButton = ???;
const showPrompt = true;
const pol = '123456';
const wrapper = shallow(<Reissue close={} disableButton={} showPrompt={showPrompt} pol={pol}/>);
});
});

The void keyword in this context is used to indicate that the function returns no value, hence you can just use an empty closure () => {}.
If you are using jest, you can also use jest.fn(), which will behave the same but has the benefit of capturing information that will help you during your tests (e.g. how many times the function have been called)
https://jestjs.io/docs/mock-functions

close and disableButton are functions so you should pass functions to them, even if empty empty ones -
const wrapper = shallow(<Reissue close={()=>()} disableButton={()=>()} showPrompt={showPrompt} pol={pol}/>);

Related

Subscribing to Map Data Structure in JavaScript doesn't work

I have been trying to observe changes on a Map Object in JavaScript but for some reason only can observe the creation of the object. Do observables not work when adding/removing data from a Map?
Here is the observable:
test(): Observable<Map<string, Object>> {
return of(this.testModel.test());
}
This is me subscribing to it:
test(): Observable<Map<string, Object>> {
let mapOb = this.testModel.test();
return Observable.create((obsrvr) => {
const originalSet = mapOb.set;
const originalDelete = mapOb.delete;
mapOb.set = (...args) => {
obsrvr.next(originalSet.call(mapOb, ...args));
};
mapOb.delete = (...args) => {
obsrvr.next(originalDelete.call(mapOb, ...args));
}
});
}
I see the log statement during the creation of the Map, but if i add any new entries to the Map nothing is logged. Anyone know why this may be happening?
I get an error at maoOb.set and mapOb.delete:
Type '(key: string, value: Object) => void' is not assignable to type '(key: string, value: Object) => Map<string, Object>'.
Type 'void' is not assignable to type 'Map<string, Object>'
You current approach doesn't seem correct when you want to listen to addition/deletion of data in a Map.
You are simply returning an Observable using of(Object Reference), this will no way know about things that you are doing with the Object you are passing with it.
You need to have an Observable which emits when you perform set() or delete() over the MapInstance.
You may modify your Map instance this way to achieve what you desire.
createObservable(mapOb) {
return Observable.create((obsrvr) => {
const originalSet = mapOb.set;
const originalDelete = mapOb.delete;
mapOb.set = (...args) => {
const setReturn = originalSet.call(mapOb, ...args);
obsrvr.next(setReturn);
return setReturn;
};
mapOb.delete = (...args) => {
const deleteReturn = originalDelete.call(mapOb, ...args);
obsrvr.next(deleteReturn);
return deleteReturn;
}
});
}
Pass the map to createObservable() method and subscribe to it. In this method, I have modified the set and delete methods of your map, so that it emits a value when those methods are called.
I have created a dummy example for the answer: Link.

Difference between arrow functions and normal functions in React Native

So I've always thought of arrow functions to be a new better and version of normal js functions until today. I was following a tutorial on how to use firestore to store data when I came across a problem that made realise the two are different and work in a weird way.
His code looked like this:
//component
function Todos() {
const [ todo, setTodo ] = useState('');
const ref = firestore().collection('todos');
// ...
async function addTodo() {
await ref.add({ title: todo, complete: false});
setTodo('');
}
// ...
}
My code looked like this:
//component
const Todos = () => {
const ref = firestore().collection('todos');
const [todo, setTodo] = useState('');
const addTodo = async () => {
const res = await ref.add({ title: todos, complete: false });
setTodo('');
};
};
Now his version worked, while mine didn't.
After changing my code to look like his, it worked. But the weird thing i realised was this: after clicking on the button that invoked that function for the first time (with his function), i changed the code back to mine and it worked the second time. I did some reading on the two functions but i couldn't get to reasoning behind why this happened.
Arrow functions and normal function are not equivalent.
Here is the difference:
Arrow function do not have their own binding of this, so your this.setState refer to the YourClass.setState.
Using normal function, you need to bind it to the class to obtain Class's this reference. So when you call this.setState actually it refer to YourFunction.setState().
Sample Code
class FancyComponent extends Component {
handleChange(event) {
this.setState({ event }) // `this` is instance of handleChange
}
handleChange = (event) => {
this.setState({ event }) // `this` is instance of FancyComponent
}
}

Typescript Error in React useScroll hook: Cannot invoke an expression whose type lacks a call signature

I have the following function definition:
const useScroll = () => {
const ref = useRef(null)
function executeScroll() {
if (ref !== null)
window.scrollTo(0, ref.current.offsetTop)
}
const htmlElementAttributes = { ref }
return [executeScroll, htmlElementAttributes]
}
export default useScroll;
Based on this function, I have the following code:
const [executeScroll, scrollHtmlAttributes] = useScroll();
const click_argueBtn = (e) => {
e.preventDefault();
executeScroll();//error
}
However, the executeScroll(); code throws the following error:
Error: Cannot invoke an expression whose type lacks a call signature
Any ideas why I receive this error? My code is based on this post.
Typescript is doing its best to determine the types automatically, and it determines that useScroll returns an array, who's elements are each () => void | { ref: /*ref type*/ } (i don't know precisely what the type on the ref object is). When you try to call executeScroll, it doesn't know whether it's a function, or an object with a ref. So since it might not be a function, you're not allowed to call it.
Instead, i'd recommend explicitly telling typescript that useScroll returns a tuple. A tuple is similar to an array, except you explicitly declare how many elements it has and what their individual types are:
const useScroll = (): [() => void, { ref: /* ref type */ }] => {
// ...etc
}
or
const useScroll = () => {
// ... etc
return [executeScroll, htmlElementAttributes] as [() => void, { ref: /* ref type */ }];
}
or if you don't like it inline, you could extract it to a type:
export type UseScrollResult = [() => void, { ref: /* ref type */ }];
const useScroll = (): UseScrollResult => {
// ...etc
}
From this, typescript now knows that element 0 of the array is () => void, and therefore it's legal to call it as a function.

Can I use the same function names when using Object.assign() in composition?

Context
I created a new object using a composition paradigm in Javascript.
const canUpdateScore = (state) => ({
update: (spell) => state.score--
})
const mage = (name) => {
let state = {
score: 100,
}
return Object.assign(state, canUpdateScore(state));
}
scorcher = mage()
scorcher.update(); // call the update method
console.log(scorcher.score) // 99
Question
Would it be confusing to name the assiging method the same as the external function that is returning that method(example below)?, or is it better to use different names (in context above)?
const updateScore = (state) => ({
updateScore: (spell) => state.score--
})
const mage = (name) => {
let state = {
score: 100,
}
return Object.assign(state, updateScore(state));
}
scorcher = mage()
scorcher.updateScore(); // call the update method
console.log(scorcher.score) // 99
The convention for using composition is "thing-doer". Your updateScore composant is a "scoreUpdater" and it "updateScore"'s.
Would write out like this:
const scoreUpdater = (state) => ({
updateScore: (spell) => state.score--
})
Now, update on it's own a rather lousy name both for clarity reasons and for design ones as well. Imagine you thing of another composant which will update the health: healthUpdater which also implements an update method. One of them will override the other.
In general, names of properties in composants should in some way, explicitly refer to the composant itself.
canUpdateScore is definitely a poor name for an object regardless are it implies a boolean, which is not the case.

Dispatch undefined after binding to class in redux

Issue with a pattern i'm trying to use with redux.
I have a a mapDispatchToProps as below,
const mapDispatchToProps = (dispatch) => {
return {
presenter: new Presenter(dispatch),
};
};
and my presenter constructor looks as below:
constructor(dispatch) {
this.dispatcher = dispatch;
}
If I check the value of it in the constructor and after it's set, all is well. However later when a method tries to use it, the value of dispatch is undefined.
If i save it to a var outside the class, i.e.
let dispatch;
class Presenter {
constructor(dispatcher) {
dispatch = dispatcher.bind(this)
}
}
I've tried using .bind() within the first constructor also but it keeps becoming undefined!
Class methods were of the form:
someMethod() {
//do stuff
}
which means they have their own this scope bound... I'd have to bind the individual methods in the constructor, such as:
constructor(dispatch) {
this.dispatch = dispatch;
this.someMethod = this.someMethod.bind(this);
}
Or turn them into => functions so they take their context from the surrounding class, i.e.
someMethod = () => dispatch(/* an action */);

Categories

Resources