How do I set a listener prop on React Native `TextInput` ref - react-native

I have a need to dynamically set the OnPressIn prop of a TextInput. I have a ref to the TextInput, but can't figure out how to set this method.
const inputRef = useRef(null);
<TextInput
...
ref={inputRef)
/>
// inputRef is passed as a prop to another component, then I try to set OnPressIn. Neither of these techniques work:
inputRef.setNativeProps({
OnPressIn: () => console.log('ONPRESS TRIGGERED'),
});
inputRef.OnPressIn = () => console.log('ONPRESS TRIGGERED');
How can I set this prop on a TextInput ref?

I believe you're missing "current".
inputRef.current.setNativeProps({
OnPressIn: () => console.log('ONPRESS TRIGGERED'),
});
Also, on what occasion does your onPressIn need to be changed? Isn't using a condition easier?
const handleOnPressIn = () => {
if (condition) {
console.log(`ONPRESS TRIGGERED condition: ${condition}`)
} else {
console.log(`ONPRESS TRIGGERED condition: ${condition}`)
}
}
<TextInput
onPressIn={() => handleOnPressIn()}
/>
If you're aiming for performance optimisation, I believe you should also consider wrapping the setNativeProps call in a useCallback() hook, as from the React Native docs on setNativeProps to edit TextInput value.

Related

React-Native Switch uncontrolled using an object doesn't change value

I have a react-native project in which I'm trying to handle the Switch component in a way that I can dynamically set an object with the boolean and its value, but I doesn't respond well:
Initially I use useEffect to process the data:
useEffect(() => {
let lista = {}
Object.entries(planes).forEach(([j, plan]) => {
lista[plan.nombre] = false
})
setSeleccion(lista)
}, []);
Then I loop through my data to load it and create the "card" dynamically with a Switch:
<Switch
offTrackColor="indigo.100"
onTrackColor="indigo.300"
onThumbColor="coolgray.500"
offThumbColor="indigo.50"
size="lg"
onToggle={(val) => toggleSwitch(val, plan.nombre)}
value={seleccion[plan.nombre]}
/>
Then toggle function:
const toggleSwitch = (val, plan) => {
setSeleccion({...seleccion, [plan]: val})
};
Now if I print the new array it shows as expected:
useEffect(() => {
console.log(seleccion)
}, [seleccion]);
But sadly the Switch remains as false visually (just goes back to its false state, so one cant toggle back to off/false).
If I do a toString(seleccion[plan.nombre]) in the render it shows [object Undefined]
Assuming that the Switch that you used is same/from react-native. There shouldn't be a prop called onToggle in Switch like you wrote below.
<Switch
offTrackColor="indigo.100"
onTrackColor="indigo.300"
onThumbColor="coolgray.500"
offThumbColor="indigo.50"
size="lg"
onToggle={(val) => toggleSwitch(val, plan.nombre)}
value={seleccion[plan.nombre]}
/>
instead, you need to use onValueChange
<Switch
offTrackColor="indigo.100"
onTrackColor="indigo.300"
onThumbColor="coolgray.500"
offThumbColor="indigo.50"
size="lg"
onValueChange={(val) => toggleSwitch(val, plan.nombre)}
value={seleccion[plan.nombre]}
/>
You can read more about the props in Switch here

React native flatlist rerender

I'm working on a flatlist that has complex child that cause expensive rerender, I need to optimize that but I'm not able to stop the rerendering with useMemo, please help me to go through this.
Here my list code:
<FlatList
data={thePosts}
extraData={thePosts}
keyExtractor={(item, index) => index.toString()}
removeClippedSubviews={true}
maxToRenderPerBatch={5}
updateCellsBatchingPeriod={30}
initialNumToRender={11}
windowSize={5}
refreshing={isRefreshing}
onRefresh={handleOnRefresh}
onEndReached={isLoading ? () => null : () => getPosts("more")}
onEndReachedThreshold={0.1}
renderItem={memoizedPost}
//renderItem={renderThePost}
ItemSeparatorComponent={renderThePostSep}
ListFooterComponent={renderThePostListFooter}
/>
here the renderPost:
const renderThePost = (props) => {
let post = props.item;
if (post[0].type == "share") {
return (
<TheSharedPost thePost={post} />
);
} else {
return <ThePost thePost={post} />;
}
};
I've tried to use memoization like this:
const memoizedPost = useMemo(() => renderThePost, []);
Now the problem is, the empty array as useMemo argument I think that only accept the first render but not working, I've tried to use [item.someProperty] but I'm not able to recognize item in the argument (item is not defined)
I've also used useCallback but still no luck, a lot o rerendering happen. Please help me to fix this. Tnz
you can use React.memo to avoid rendering of flatlist items
function TheSharedPost(props) {
/* render using props */
}
export default React.memo(TheSharedPost);
function ThePost(props) {
/* render using props */
}
export default React.memo(ThePost);

How to get props variable in detailed props React-Native

I have a custom component like this
const MyCustomComponent = ({ value, style }) => {
// I can access value & style with value and style
return <View style={style}>
<Text>{value}</Text>
</View>
}
I can called it with
<MyCustomComponent value="123" style={{ color: "blue" }} />
My question is how to get arguments or alyelse to get all props passed to my component?
In native function, i can use arguments to get allProps as an Array and set it in a new variable like const allProps = arguments[0]
What about in arrow function?
What you have here is a functional component, it is built as such that it only receives one object - that is props. When you did this: const MyComponent({value, style}) you destructured the prop object, extracting only the two variables.
You should instead do this:
const MyCustomComponent = (props) => {
//you can access the values like this
console.log(props.style, props.value)
//or you can access them like this which is the same thing you did
//earlier
const {style, value} = props;
console.log(style, value)
return (
...
)
}
Keep in mind that you need to have React in scope, so be sure to import it at the top:
import React from 'react';
Functional components are very well explained in React documentation: https://reactjs.org/docs/components-and-props.html
Do you want to get 'value' and 'style' props using a single variable?
You can use:
const MyCustomComponent = (props) => {
// I can access value & style with value and style
return <View style={props.style}>
<Text>{props.value}</Text>
</View>
}

How can I check value of the refreshControl prop in jest for my react-native app?

I am trying to do a jest unit test which simply confirms that the refreshControl prop is active in my ScrollView.
I currently have a component that essentially renders the following
<ScrollView
refreshControl={
<RefreshControl
refreshing={this.state.refreshing}
onRefresh={this._onRefresh}
/>
}
{children}
/>
It works fine in practice, and in my test, I am checking to confirm that the prop is as expected.
import { RefreshControl } from 'react-native'
const layout = shallow(<Element />)
const refreshControl = <RefreshControl
onRefresh={jest.fn()}
refreshing={false}
/>
expect(layout.prop('refreshControl')).toEqual(refreshControl)
I then get this error when running my test:
Expected value to equal:
<RefreshControlMock onRefresh={[Function mockConstructor]} refreshing={false} />
Received:
<RefreshControlMock onRefresh={[Function mockConstructor]} refreshing={false} />
I assume it's because the instance of the onRefresh function differs, but not sure how to control that. Does anyone perhaps know?
Please find below steps to call Pull to Refresh to cover coverage.
First, get access to the scrollView component through testID
Fetch refresh control present in the scroll view component
call onRefresh from test case
I have added the below Example for reference.
test('refresh control', async () => {
const props = createTestProps();
const component = render(
<Provider store={store}>
<ScrollViewComponent {...props} />
</Provider>
);
const scrollView = component.getByTestId('refreshControl');
expect(scrollView).toBeDefined();
const { refreshControl } = scrollView.props;
await act(async () => {
refreshControl.props.onRefresh();
});
});
Just realised that I need to check that the function is the same one I pass into the component, in the test, so basically, the function in the component that matches.
this._onRefresh
MW UMESH's answer helped me quite a lot (and I therefore upvoted it) but since you get the refreshControl prop synchronously, you can remove the async test here.
So replace
await act(async () => {
refreshControl.props.onRefresh();
});
With
refreshControl.props.onRefresh();
And the reload mechanism will trigger.

How to initiate props when rendering Component?

I have a Login Component where I want the user to choose Service from a Service Catalogue. The Picker gets and sets values to redux:
<Picker
selectedValue={this.props.service.id}
onValueChange={itemValue => this.props.setServiceType(itemValue)}>
{service_catalogue.map(service =>
<Picker.Item key={service.id} label={service.id} value={service.id} />
)}
</Picker>
But I don't know how to properly set the initial value. I set the default value in componentDidMount (the first item in the Catalogue), but I think componentDidMount is trigged on update? Is there a lifecycle function that is only triggered on rendering Component in React Native?
componentDidMount() {
this.props.setServiceType(service_catalogue[0].id)
}
So the problem that I'm facing is that even though the user might choose "Instructor" the service becomes service_catalogue[0] = "Cleaner". And if I don't setServiceType on componentDidMount no Picker appears, as this.props.service.id doesn't exist.
You can set default value for the props on the following way:
...
YourComponent.propTypes = {
myState: PropTypes.string,
}
YourComponent.defaultProps = {
myState: 'default value',
};
const mapStateToProps = state = ({
myState: state.myState,
});
export default connect(mapStateToProps)(YourComponent);
More info: https://reactjs.org/docs/typechecking-with-proptypes.html#default-prop-values