React Native Arrow Syntax Explanation - javascript

I am reviewing some code and was unable to find a breakdown of this arrow function syntax. Could someone help explain what the parameters ({ match, onOpen }: MatchListItemProps) mean?
import React from 'react';
import { ListItem } from 'react-native-elements';
import { StyleSheet } from 'react-native';
type MatchListItemProps = {
match: User,
onOpen: Function
};
const styles = StyleSheet.create({});
const TestScreen = ({ match, onOpen }: MatchListItemProps) => {
const { name, image, message } = match;
return (....

Could someone help explain what the parameters ({ match, onOpen }: MatchListItemProps)mean?
This code is using typescript and destructuring. Let me get rid of both for a second, then add them back in. Here it is in pure javascript without destructuring:
const TestScreen = (props) => {
let match = props.match;
let onOpen = props.onOpen;
Now i'll add back in the typescript. A variable can be followed by a colon and then a type. This information is used to catch type errors at compile time.
const TestScreen = (props: MatchListItemProps) => {
let match = props.match;
let onOpen = props.onOpen;
And then adding in the destructuring. This is a shorthand to pluck values off an object and assign them to local variables:
const TestScreen = ({ match, onOpen }: MatchListItemProps) => {

Since the parameter is an object, you can deconstruct it inside the parameter.
For instance, take a look at this code
let person = {
name: 'Felipe',
age: '23'
}
You could take the values in this form
let name = person.name
let age = person.age
Or you could use a shortcut with destructuring assignment
let { name, age } = person
Finally, if the variable person inside a parameter, you can deconstruct it inside the very parameter
logPersonNameAndAge = ({ name, age }) => {
console.log(name)
console.log(age)
}
So that you could call it passing the entire object
logPersonNameAndAge(person)

Your code is TypeScript, not just JavaScript. : MatchListItemProps is a type annotation that's used by TypeScript, which is used to catch many common errors at compile time instead of at runtime. ({ match, onOpen }) => { ... is a destructuring, which means the function takes an object, and brings into scope variables called match and onOpen containing whatever was in the object with those names. It's roughly equivalent to obj => { let match = obj.match, onOpen = obj.onOpen; .... In turn, const TestScreen = obj => { ... is a lambda, which is roughly equivalent to function TestScreen(obj) { ....

Related

How to export functions from a custom hook

The basic structure of my hook:
const useMyHook = () => {
const func1 = (): boolean => { ... }
const func2 = (type: "type1" | "type2"): boolean => { ... }
const func3 = (): boolean => { ... }
return {
func1, func2, func3
}
}
export default useMyHook
I'm currently using it like this, which works in dev, but breaks my build.
import useMyHook from "../hooks/useMyHook";
const { func1 } = useMyHook()
const handleSubmit = (e: React.FormEvent) => {
e.preventDefault();
const isValid = func1();
if (isValid) {
// do more things
}
}
return (
<form>...</form>
)
When running yarn build, I am faced with this error:
Objects are not valid as a React child (found: object with keys {func1, func2, func3}). If you meant to render a collection of children, use an array instead.
My attempt at solving this was to export my custom hook functions in an array, as the error seemed to suggest.
return [
func1, func2, func3
]
And using it like this:
const [ func1 ] = useMyHook();
const isValid = func1();
TypeScript is not happy with this:
An argument for 'type' was not provided.
But this is confusing, because func1 does not accept a type argument as func2 does.
Questions
Is there some way I work around this build-time error and export the { } of functions? This feels like the cleanest approach.
If there is no way to achieve 1, how can I properly use the exported array of functions without my types being misread?

Using a variable as object name in React

So this is an example of the problem I am having.
import { useState, useEffect } from "react";
import symbols from "./Symbols.js"
const DrawSymbol = (type) => {
const [state, setState] = useState("");
useEffect(() => {
const g = symbols.find((obj) => {
return obj[type];
});
setState(g.url);
},[]);
return <div>{state}<div>
};
Symbol.js has svg data so Ill just truncate it for legibility
const symbols = [
{
"0":{
"url":"data:image/svg+xml;base64,PHN2ZyB4bWxucz..."
}
},
{
"1":{
"url":"data:image/svg+xml;base64,PHN2ZyB4bWxucz0naHR0cD....."
}
},
{
"2":{
"url":"data:image/svg+xml;base64,PHN2ZyB4bWxucz0naHR0cDov..= "
}
},
{
"2B":{
"url":"data:image/svg+xml;base64,PHN2ZyB4bWxucz0naHR0c.... "
}
},
.....
]
export default symbols;
Symbols.js exports an array of objects to this file. The issue here is that if I were to manual say obj['name'] it works and it returns the requested object but if I try to use the passed variable name obj[type] it comes up as undefined. Using the debugger in Firefox I can see that the variable being passed does indeed have a String value, but it still never works. Its driving really mad.
const DrawSymbol = (props) => {
const [state, setState] = useState("");
useEffect(() => {
if(props.type) {
// `symbols` is a array of object. you need to find one object from that array
const g = symbols.find((obj) => obj.type === props.type);
setState(g?.text);
}
}, [props]);
return <div>{state}<div>
};
Try this out.
I don't exactly know what you are up to without actually seeing your Symbol.js file. But a quick glance probably shows that shouldn't you be destructuring the type like const DrawSymbol = ({type}) => { ... rest of the code } if you are passing the type as props into this component.? If not then you are actually using the find method incorrectly. Find method finds the first element it matches according to the condition given. Here you actually are directly returning which would obviously return false since you are not giving any condition using which it would find it inside the array.
The correct way would be -
useEffect(() => {
if(type) {
const g = symbols.find((obj) => obj.type === type);
setState(g.text);
}
}, [type]);
Here in the above code it would return exactly the thing you need since here we are giving the condition using which it would match it inside the array.
You can solve this with useMemo:
import { useMemo } from "react";
import symbols from "./Symbols.js";
const DrawSymbol = ({type}) => {
const symbolText = useMemo(() => symbols.find(s => s.type === type)?.text ?? '', [type]);
return <div>{symbolText}<div>;
};

JavaScript input query string does not accept space tab but letter

I am using React-native typescript for my app . I have a TextInput, where user can pass some value(letter/letters) that value pass it to the Api's query string, and give search result. I have made one helper function which does not accept any space. It only accepts letter/letters.
I want to make helper function which take spaces but it will only trigger when there is letter/letter. It's really hard to explain. But I found Linkedin has this kind search filter, which logic I want implement in my app. But I don't know how to do that.
This is my code
import debounce from 'lodash/debounce';
import React, { useState, useRef } from 'react';
const SearchScreen = () => {
const [searchText, setSearchText] = useState('');
const [searchedText, setSearchedText] = useState('');
const delayedSearch = useRef(
debounce((text: string) => {
_search(text);
}, 400),
).current;
const _clearSearch = () => {
if (searchText.length === 0) {
Keyboard.dismiss();
}
setSearchText('');
setSearchedText('');
};
const _search = (text: string) => {
setSearchedText(text);
};
const removeExtraSpace = (s: string) => s.trim().split(/ +/).join(' '); // this is my helper function which does not accept white space
const _onSearchChange = (text: string) => {
setSearchText(removeExtraSpace(text)); // in here I am using the helper function
delayedSearch(removeExtraSpace(text)); // in here I am using the helper function
};
return (
<Container>
<SearchBar
text={searchText}
onClearText={_clearSearch}
onChangeText={_onSearchChange}
/>
<ProductSearchResult
queryString={searchedText} // in here I a passing Search
/>
</Container>
);
};
export default SearchScreen;
I made a mistake. My function works fine. But mistakenly I passed function to local state.
It should be like this:
const _onSearchChange = (text: string) => {
setSearchText(text);
delayedSearch(removeExtraSpace(text));
};

Cannot access react state from callback

I have the following components:
const ParentComponent: React.FC = () => {
// Somewhere in the code, I set this to some value
const [newType, setNewType] = useState<any>(undefined);
// Somewhere in the code, I set this to true
const [enableAddEdge, setEnableAddEdge] = useState(false);
const addEdge = (data: any) => {
console.log("newType", newType); // This is undefined
}
return (
...
<VisNetwork
newType={newType}
onAddEdge={addEdge}
enableAddEdge={enableAddEdge}
/>
...
)
}
export default ParentComponent;
interface Props {
newType: any;
onAddEdge: (data: any) => void;
enableAddEdge: boolean;
}
const VisNetwork: React.FC<Props> = (props: Props) => {
const options: any = {
// Some vis-network specific option configuration
manipulation: {
addEdge: (data: any, callback: any) => props.onAddEdge(data);
}
}
...
// Some code to create the network and pass in the options
const network = new vis.Network(container, networkData, options);
useEffect(() => {
if (props.enableAddEdge) {
// This confirms that indeed newType has value
console.log("newType from addEdge", props.newType);
// Call reference to network (I name it currentNetwork)
// This will enable the adding of edge in the network.
// When the user is done adding the edge,
// the `addEdge` method in the `options.manipulation` will be called.
currentNetwork.addEdgeMode();
}
}, [props.enableAddEdge])
useEffect(() => {
if (props.newType) {
// This is just to confirm that indeed I am setting the newType value
console.log("newType from visNetwork", props.newType); // This has value
}
}, [props.newType]);
}
export default VisNetwork;
When the addEdge method is called, the newType state becomes undefined. I know about the bind but I don't know if it's possible to use it and how to use it in a functional component. Please advise on how to obtain the newType value.
Also, from VisNetwork, I want to access networkData state from inside options.manipulation.addEdge. I know it's not possible but any workaround? I also need to access the networkData at this point.
You need to useRef in this scenario. It appears const network = new vis.Network(container, networkData, options); uses the options from the first render only. Or something similar is going on.
It's likely to do with there being a closure around newType in the addEdge function. So it has stale values: https://reactjs.org/docs/hooks-faq.html#why-am-i-seeing-stale-props-or-state-inside-my-function
In order to combat this, you need to useRef to store the latest value of newType. The reference is mutable, so it can always store the current value of newType without re-rendering.
// Somewhere in the code, I set this to some value
const [newType, setNewType] = useState<any>(undefined);
const newTypeRef = useRef(newType);
useEffect(() => {
// Ensure the ref is always at the latest value
newTypeRef.current = newType;
}, [newType])
const addEdge = (data: any) => {
console.log("newType", newTypeRef.current); // This is undefined
}

From JavaScript source: Can you tell me about the meaning of the operator?

// #flow
export const LETSEE_LOADED: 'LETSEE_LOADED' = 'LETSEE_LOADED';
export const START_LOADING: 'START_LOADING' = 'START_LOADING';
export const STOP_LOADING: 'STOP_LOADING' = 'STOP_LOADING';
export const letseeLoad = () => ({ type: LETSEE_LOADED });
export const startLoading = () => ({ type: START_LOADING });
export const stopLoading = () => ({ type: STOP_LOADING });
Please resolve any questions that your company has encountered while analyzing JavaScript source.
I am wondering what the meaning of the: operator next to export const LETSEE_LOADED in the above source. It does not seem to be a ternary operator.
You can just say export const LETSEE_LOADED = 'LETSEE_LOADED', but what about the: operator?
The : says that the type of the variable is a exact string LETSEE_LOADED and only a value containing that exact string can be assigned to the variable. The variable is declared as const, so it can't be modified after the assignment, but you can misstype the value of the variable at the initialization, so why in the combination with the const the type is also provided.

Categories