What does this notation mean in React-Native? - reactjs

I took over an unfinished react-native project and this notation confused me. An anonymous function is written in curly brackets and given various arguments ( handleChange, handleBlur, handleSubmit, values). Where do we define those arguments ? Where can an anonymous function get the data for these arguments? What exactly is the function of these arguments?
This codeblock was inside the JSX template between various react-native elements.
Entire project was built along TypeScript.
return (
<ScrollView
contentContainerStyle={{
flex: 1,
flexGrow: 1,
padding: spacing.xl,
}}
>
<KeyboardAvoidingView style={{ flex: 1 }}>
<TouchableWithoutFeedback
onPress={Keyboard.dismiss}
style={{ flex: 1 }}
>
<ImageBackground
source={require('#/assets/images/text-bg.png')}
resizeMode="cover"
minHeight="100%"
flex={1}
>
<Box flex={1}>
<Text color="loginHeader" fontSize={36} marginBottom="xl">
Login
</Text>
<Formik
initialValues={{ phoneNumber: '' }}
onSubmit={async values => await submitLogin(values)}
>
{({ handleChange, handleBlur, handleSubmit, values }) => (
<>
<Box width="100%" marginBottom="xl">
<TextInput
keyboardType="phone-pad"
placeholder="Phone Number"
placeholderTextColor={colors.neutral500}
value={values.phoneNumber}
onChangeText={handleChange('phoneNumber')}
onBlur={handleBlur('phoneNumber')}
/>
</Box>
<Button
label="Login"
onPress={handleSubmit}
backgroundColor="buttonBackground"
padding="md"
borderRadius="sm"
shadowColor="black"
shadowOpacity={0.4}
shadowRadius={8.3}
elevation={20}
shadowOffset={{ width: 0, height: 6 }}
/>
</>
)}
{/* <Box width="100%" marginBottom="xl">
<TextInput
secureTextEntry={true}
placeholder="Password"
placeholderTextColor={colors.neutral500}
/>
</Box> */}
</Formik>
</Box>
</ImageBackground>
</TouchableWithoutFeedback>
</KeyboardAvoidingView>
</ScrollView>
)

This technique is known as render props. Instead of passing JSX to an element as it's children, you pass a function which takes data from the parent as its arguments. In your example, Formik calls its children prop with those arguments - they are controlled and defined by the Formik component.

This anonymous function is getting passed to another component as children prop, which is a variant of render prop pattern, a pattern used to share functionality between components.
Like the piece of code you posted, a component like Formik manages some functionality for an input, all of which are encapsulated within the Formik component. to share them, it asks you for a prop that should be function, and can be named anything, but mostly render or children.
Inside itself, the Formik component is structured like this:
const handleChange ... // some logic about input being changed
later in it its return it calls that function props you passed like this:
return <>{props.render({handleChange})</>
In your case, Formik is using the children prop, like this:
return <>{props.children({handleChange})</>

Related

How to pass a custom component to title props in MUI tooltip?

I am trying to customize a Tooltip component by passing a custom component like the image.
At first time, I've used Popover once, but the main reason why I am going to use Tooltip is because of the arrow of Tooltip.
Basically, I am using React and MUI v5 running on TypeScript.
I built a custom Tooltip component like this.
<Tooltip
open={open}
arrow
placement={placement}
title={
<Box component="span" p={1} width={width}>
<IconButton size="small" onClick={onClose}>
<CloseIcon />
</IconButton>
<Box my={2} px={4}>
<Typography my={2}>
{message}
</Typography>
<FormControlLabel control={<Checkbox defaultChecked />} label="Don’t show again" />
</Box>
</Box>
}
{...rest}
>
{children}
</Tooltip>
It seems to be working, but it keeps saying an error message Tooltip title. Zero-length titles string are never displayed. 'title' is specified more than once, so this usage will be overwritten.ts(2783).
How can I resolve this issue, or should I use Popover rather than Tooltip component?
You need to move title prop after {...rest} parameters.
It looks like your rest paramaters already have title property inside, so basically you are overwriting your title with something else from rest parameters (at least typescript thinks that).
It is the same as:
const foo = { title: 'aaaa', sth: 'cccc' };
const bar = { title: 'bbbb', ...foo}
console.log(bar.title); // => 'aaaa'
If you open this code in some environment with typescript support, it will also show same error as yours, see
What you need to do is:
const foo = { title: 'aaaa', sth: 'cccc' };
const bar = { ...foo, title: 'bbbb' };
console.log(bar.title); // => 'bbbb'

Date component passing the value to parent component react typescript

I want to create a date component on a child component and show on the screen (on the parent component) the selected date. Moreover I have two problems:
I am not managing to make the components talk with each other. I can print on the console the answer from the child component but I cannot pass to the parent component
When I select date "custom" on my dropdown I want to select a start and end date but I can't do it, when I select one of the dates (start or the end) the other updates itself automatically.
Any help is welcome :)
Here is my codesandbox: https://codesandbox.io/s/date-picker-forked-h1u9s?file=/src/App.tsx
This is how I call the date component
export default function App() {
return (
<div>
<DateComponent />
<div>Your chosen date was: </div>
</div>
);
}
This is the date component:
return (
<MuiPickersUtilsProvider utils={DateFnsUtils}>
<div className="App">
<div>
<ReactSelect
value={selectedOption as ValueType<OptionType>}
onChange={(option) => handleChange(option)}
isMulti={false}
options={options}
/>
{selectedOption === DateValueEnum.Custom ? (
<div style={{ display: "flex" }}>
<div style={{ width: "50%", float: "left", paddingRight: "5px" }}>
<DatePicker
fullWidth
margin="normal"
required={true}
error={false}
invalidLabel={"Several values..."}
value={selectedDate}
onChange={(newDate) => setSelectedDate(newDate)}
format="MM/dd/yyyy"
/>
</div>
<DatePicker
fullWidth
margin="normal"
required={true}
error={false}
invalidLabel={"Several values..."}
value={selectedDate}
onChange={(newDate) => setSelectedDate(newDate)}
format="MM/dd/yyyy"
/>
</div>
) : null}
</div>
</div>
</MuiPickersUtilsProvider>
);
};
You can share state or function between components.
There is many ways to do it
You can share state directly from Parent component to children, before sharing state you need to create one with React useState hook
like so:
const [date, setDate] = useState("")
<DateComponent setDate={setDate} />
Here we passed the setDate function to the children component.
When we will call that function in DateComponent we will change the Parrent component's state
props.setDate("date")
read about state and life cycle here, it will help you a lot.
Also read about hooks, which were used previosly.
Another way to pass data between components is useContext it's more complicated way, or you can use library like Redux, Mobx.
About "custom" selected option, you created only one state for two options, so when you pick the date, both are changed. To fix it you nedd to add second state.
here the fixed version: sandbox

How to underline a specific word in a string for a React Native button

I'm using a Button component from react-native-elements and for the title prop I would like to underline one of the words, is this possible?
button.js:
<Button
buttonStyle={styles.buttonStyle}
titleStyle={styles.titleStyle}
containerStyle={styles.containerStyle}
title={title}
onPress={onPress}
disabled={disabled}
disabledStyle={[styles.disabledStyle]}
/>
I'm using it like this:
<Button
title={'First line \nSecond line'} // <- How to underline First & Second?
onPress={() => console.log('pressed button')}
/>
How do I underline the words First and Second?
I tried doing title={`${First} line \n${Second} line`} where First and Second is a <Text style={{textDecoration: 'underline}}>First</Text> but I'm getting [object, Object] since it's not an expression
<Button> implementation in React Native Elements indeed does support passing component as title property value - but in your code you try to pass those as text. That's what you might try instead:
const ButtonTitle = (
<>
<Text style={{textDecoration: 'underline'}}>First</Text>
<Text style={{textDecoration: 'underline'}}>Second</Text>
</>
)
<Button title={ButtonTitle} />
For situations like this, I generally will use React.ReactNode as the type for title instead of a string. This will be backwards-compatible, as strings are valid ReactNodes, but it also allows you to do this:
// style example
const style = Stylesheet.create({
underline: { textDecoration: 'underline' },
});
// Implementation in component
title={
<Text>
<Text style={style.underline}>
First line
</Text>
<Text style={style.underline}>
Second line
</Text>
</Text>
}
Reminder that the original will also still work as ReactNode is a type which includes string:
title={'First line \nSecond line'}

Passing props to children in a composition model

I'm using composition model a, I have one parent element that have many children.
I'm wondering if it is possible to get the props of the parent element inside the children.
For now i'm passing the same props to all the component (parent and child) but I guess there is better way to do that.
Here the parent element
const ImageTop = ({ results, children }) => {
const navigation = useNavigation();
return (
<>
<ImageBackground
style={{ height: height * 0.25, width: "100%" }}
source={imageToDisplay(results)}
>
<Pressable style={styles.blocArrow} onPress={() => navigation.goBack()}>
<Ionicons name="arrow-back-outline" size={32} color="white" />
</Pressable>
<TransparentsBar results={results} />
</ImageBackground>
<View style={{ marginLeft: 15, paddingTop: 15 }}>{children}</View>
</>
);
};
And here I'm passing components as children of the parent component :
const DetailsEvents = ({ route }) => {
const [results] = useState(route.params.item);
return (
<ScrollView showsVerticalScrollIndicator={false}>
<ImageTop results={results}>
<GenreAndTitle results={results} />
<Address results={results} />
<Date results={results} />
<CTA results={results} />
<Description results={results} />
<OrganizedBy results={results} />
</ImageTop>
</ScrollView>
);
};
So as you can see I'm sending the same props "Results" to all components which is ugly ... I'd like to send the props only to the parent and the children get access to that props. Is there any way to do that ?
Thank you
You can use React Context. This will remove the redundancy regarding sending same props to all those child components separately. What you will be doing is create a context having the value you want your application to use globally and wrap your root elements with that context's Provider. Then the value will be available to all your child components which you can access and modify with useContext.

Render Picker Items from React-Native picker to populate drop-menu selections

I am successfully using the react-native picker to render a drop-menu in one of my components. Right now, in the picker code I am hardcoding the values used to populate the drop-menu items. What I'd ideally like to do is pass these in as props, and have them dynamically generate as many items as necessary within the picker. I'm not sure how to do that, though. I tried using a for-loop but I can't run that kind of conditional logic within the component code itself. This is what it looks like with hard coded values.
export const DropDownMenu = (props) => {
const [selectedValue, setSelectedValue] = useState(null);
return (
<View style={styles.container}>
<Picker
selectedValue={selectedValue}
style={{ height: 50, width: 150 }}
onValueChange={(itemValue, itemIndex) => {
props.onSelectMenuValue(itemValue),
setSelectedValue(itemValue)
}}
>
<Picker.Item label="A" value="a" />
<Picker.Item label="B" value="b" />
<Picker.Item label="C" value="c" />
</Picker>
</View>
);
}
How could I render Picker.Item values based on the props passed in?
You can pass an options prop as an array of objects with a label and a value property and use map like this:
<Picker /*whatever you need for picker here*/>
{props.options.map(option => <Picker.Item label={option.label} value={option.value}/>)}
</Picker>

Resources