Passing Params in The Same Screen. React Native - react-native

I know how to pass parameters to other screen. For example:
<Flatlist
data={SOMEDATA}
renderItem={(itemData) => (
<Button
onPress={() => {
props.navigation.navigate("myScreen", {
myId: itemData.item.id,
})
}}
>
</Button>
/>
Then I can access myId on the myScreen screen by props.route.params.myId, But I don't know how to access it in the same screen I am using (same js file). if I write props.route.params.myId, I will get this error :
undifined is not an object (evaluating 'props.route.params.myId'
any help please?

are you trying to set a property in the state of your current screen?
if so, what you need is a state
assuming you are using a functional react component and not a class based component, what you need to do is to introduce a state to your component
const [state, setState] = useState(initialState);
when ever you want to change your state, you just need to call the setState(myNewObj) function,
whenever you want to access your state
you can just call for state
the initiateState can be anything
in your case something like
const [myId, setMyId] = useState(-1);
I suggest you take alook at the official React Documentation
https://reactjs.org/docs/hooks-reference.html#basic-hooks

Related

how to change element that fits a component to an element that fits a function in react native

I am a new react native developer, I found a component and I want to use it in a function, but it is not clear to me how I would change it, can I get a help?
Here is the component
import TagInput from 'react-native-tag-input';
...
<TagInput
value={this.state.emails}
onChange={(emails) => this.setState({ emails })}
labelExtractor={(email) => email}
text={this.state.text}
onChangeText={(text) => this.setState({ text })}
/>
I got the code from here https://bestofreactjs.com/repo/jwohlfert23-react-native-tag-input
I guess you are asking how to adapt the code to fit the functional component, which includes converting the this.setState.
React provides some thing called React hooks, which you can think of as a way to replace states and lifecycles. You can read more about it here here
In your case, it would go like this:
import { useState } from 'react';
...
// useState can only be called inside functional components
const [emails, setEmails] = useState([]);
const [text, setText] = useState('');
...
<TagInput
value={emails}
onChange={(emailTags) => setEmails(emailTags)} // to avoid naming confusion
labelExtractor={(email) => email}
text={text}
onChangeText={(inputText) => setText(inputText)}
/>
you don't need to convert the component itself, you can use it as it is, but you need to change its implementation.
Basically, if you want to use function components, which is highly recommended now, you need to change the usage of the state in the component which will contain the <TagInput>.
Instead of using "this" which points to the class itself, you need to implement a hook called useState.
You can find it the docs here: https://reactjs.org/docs/hooks-state.html

How to create an rxjs Observable from TextInput (either onChange or onTextChange)

I want to create an observable from a change event that gets fired on a React Native TextInput component. TextInput comes with 2 change props that I'm aware of (onChangeText and onChange). From what I gather, you need to use onChange if you want access to the native event you need to use onChange.
I don't know much about the native event object. I am trying to create an rxjs observable using fromEvent.
First I created a ref in my functional component like this:
const sqftRef = useRef().current
Then I attached this ref to the TextInput component like this:
<TextInput
ref={sqftRef} // attach a ref
label='Sqft'
mode='flat'
textContentType='none'
autoCapitalize='none'
keyboardType='numeric'
autoCorrect={false}
value={String(formValues.sqft)}
dense
underlineColor={colors.colorOffWhite}
onChangeText={(text) => setText(text)}
onChange={e => {
// somehow create an observable from this event ???
}}
style={styles.inputStyles}
theme={inputTheme}
/>
I tried to create an Observable using fromEvent like this but it doesn't work. I get undefined is not an object (evaluating target.addEventListener):
fromEvent(sqftRef, 'onChange').subscribe(value => console.log(value))
I know my approach is all wrong. Hoping someone can point me in the correct direction.
I would emit events you need into a subject, then subscribe to the subject in other parts of your code.
Here's a simple React example that should get you started
function App() {
const textChange = new Subject<string>();
useEffect(() => {
// subscribe to
const subscription = textChange.asObservable().subscribe(console.log)
return () => subscription.unsubscribe()
}, [])
// Emit events with a subject
return <textarea onChange={(e) => {
textChange.next(e.target.value)
}}>
</textarea>
}
render(<App />, document.getElementById('root'));
Check out the example here: https://stackblitz.com/edit/react-ts-akoyfv
I think the problem is with assigning the current directly to the sqftRef. Try to define it without current, but use current when creating the Observable, like the following:
const sqftRef = useRef();
Then create the Observable within useEffect to make sure that the DOM is ready:
useEffect(() => {
fromEvent(sqftRef.current, 'onChange').subscribe((value) =>
console.log(value)
);
});
OK, I was able to figure it out with the help of Amer Yousuf and Alex Fallenstedt.
I did something similar to what Alex suggested, modifying his solution for React Native. One reason his solution wasn't working for me is that it is important to use the useRef hook to prevent the Observable from being re-created on each render. If the observable is recreated (on a re-render) and useEffect doesn't run again, then we won't have an active subscription to the newly (re-created) observable (useEffect never runs again). That's why my call to sqft$.next was originally only being called once (the first time until we re-render).
My solution looks like this:
let sqft$ = useRef(new BehaviorSubject(0)).current
useEffect(() => {
const sub = sqft$.subscribe({
next: (val) => {
// just testing stuff out here
updateForm('sqft', val)
updateForm('lot', val * 2)
}
})
// this is only relevant to my use case
if (activeReport) sqft$.next(activeReport.sqft)
return () => sub.unsubscribe()
}, [activeReport])
and of course I call this in onChangeText:
onChangeText={(text) => {
sqft$.next(text)
}}
So this is working right now. I still feel like there may be a better way using onChange(e => ...stuff). I will leave this question open for a little bit in case anyone can break down how to do this using nativeEvent or explain to me how I can access an event off the TextInput component.

Query in react native about sliding up panel

In React Native iOS, I would like to slide in and out of a like in the following picture.
So I installed this https://github.com/octopitus/rn-sliding-up-panel for ease.
but this error is showing =>
i cant understand whats wrong, I am new to react native. Please Help!
You cannot access variable called _panel from this object because you are inside a function itself. besides you are using function based react, in order to create a reference check useRef() hook or switch to class based component and then you can use this._panel;
smthg like this:
function AccessingElement() {
const elementRef = useRef();
const onPress = () => {
// e.g
elementRef.current.show();
}
return (
<View ref={elementRef}>
...child views
</View>
);
}

How do I get TouchableOpacity to call functions in a specifid order?

I am trying to set the state of a component prior to making the API call. The problem is the API call being called first. Here is what I have.
onPress={() => {
setMeal('dinner');
addToLogButtonPressed();
}}
When I press the button addToLogButtonPressed(); calls first which causes an error.
How to I call setMeal before addToLogButtonPressed?
I think you can use useEffect to do that
const [meal, setMeal] = useState('')
useEffect(() => {
addToLogButtonPressed();
}, [meal])
onPress={() => {
setMeal('dinner');
}}
I also face this problem for my previous project simply just pass meal value to your addToLogButtonPressed() and access it inside the function.
If you are not using "dinner" value anywhere else you can skip setting state it will save you one Re-render.
onPress={() => {
setMeal('dinner');
addToLogButtonPressed('dinner'); // like this
}}

React Native FlatList Not Re-Rendering after Asyncronous operation

I have an async function like this:
getDeals() {
if(this.props.user) {
this.setState({loading: true});
this.setState({deals: []});
var parameters = {
zip: this.props.user.zip,
sort: 'All',
category: this.props.selectedCategory,
company: this.props.user.company,
page: null,
user: this.props.user,
search: null
}
axios.post(`${constants.api}/grab-deals/`, parameters)
.then((response) => {
this.setState({totalDeals: response.data.length});
this.setState({deals: response.data, loading: false, refreshing: false});
this.forceUpdate();
})
}
}
And a FlatList component Like this:
<FlatList data={this.state.deals} style={{flex: 1, padding: 10}} extraData={this.state} keyExtractor={this.keyExtractor} renderItem={this.renderDeal.bind(this)} />
Here is the keyextractor:
keyExtractor = (item, index) => item.id;
When I call this.getDeals() the first time it works great. However when I call it a second time the axios call get's all of the correct data, but the flat list still keeps old data (it doesn't remove items that aren't in the new call).
How do I get the FlatList to always reflect the returned data?
Call this.getDeals() in componentWillUpdate() and update props?
I believe you confussing what props and state is for. Basically state is used for things that could change during the lifecycle of the component and props are kept immutable. I use them for behavior.
Unless you are changing the parameters for the getDeals function on the second call, see that all of the properties are based on the props, which are not always updated.
RN has a method called componentWillUpdate that is triggered with the new props which you can then be used to update the component itself. If you want to keep using props in your getDeals method, you will need to check if the props have changed (this happens when the parent updates the child with new props) and then trigger again the data fetch.
If this does not help, please post more code.
According to the docs you need to set the state.selected value
By passing extraData={this.state} to FlatList we make sure FlatList
itself will re-render when the state.selected changes. Without setting
this prop, FlatList would not know it needs to re-render any items
because it is also a PureComponent and the prop comparison will not
show any changes.