Accessing state inside .jsx element - javascript

If I have an element like this:
const CardWebView = () => {
const url = 'xxx';
return (
<WebView
source={{
uri: url,
}}
onNavigationStateChange={this.onNavigationStateChange}
startInLoadingState
javaScriptEnabled
style={{ flex: 1 }}
/>
);
};
How do I use state to change the url, for example?
I've tried var url = this.state.url but this gives me an error. This specific portion of code uses arrow functions and I'm not too familiar with them.

You should use React Hooks on Functional Component - Using the State Hook – React
import React, { useState } from 'react';
function Example() {
// Declare a new state variable, which we'll call "count"
const [count, setCount] = useState(0);
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>
Click me
</button>
</div>
);
}

You need to define a React.Component with a render method. You can't have state if you're not in a component
const CardWebView = <CardWebView />
class CardWebView extends React.Component{
constructor(props) {
super(props);
this.state = {url: 'xxx'};
}
render() {
return (
<WebView
source={{
uri: this.state.url,
}}
onNavigationStateChange={this.onNavigationStateChange}
startInLoadingState
javaScriptEnabled
style={{ flex: 1 }}
/>
);
}
};

If you want to use state from a functional component, you need to use the useState hook
It is fairly simple to use, just define the initial value, the callback to change it and the name of the state variable and you're set. Then you can use the callback to alter the state variable whenever you need to.
a simple example:
import React, { useState } from 'react';
import { Text, View } from 'react-native';
const App = () => {
const [url, setUrl] = useState('something')
return (
<View>
<Text>{url}</Text>
<Text onPress={() => setUrl('something new')}>Click me</Text>
</View>
);
}
export default App;

Related

Why can't I call the parent function passed as props to child component?

What I am trying To Do
I am building a simple expo managed audio player app. On my App Screen, I need display a list of songs. When a user clicks on the song, it plays and once the play finishes, the "Songs Played" at the bottom of the page should increase. I am using expo-av API for this.
Here is the breakdown of the app:
App.js
Here I have an array (Data) that holds the songs. To keep it simple, I am using the same song for all elements. count variable holds the count of songs and there is a function (IncreaseCount) which is passed to the ChildComponent as prop. Flatlist is used to render the ChildComponents
import { View, Text, FlatList } from 'react-native'
import React, {useState} from 'react'
import ChildComponent from './ChildComponent';
const Data = [
{
key: "1",
song: "https://www2.cs.uic.edu/~i101/SoundFiles/CantinaBand3.wav"
},
{
key: "2",
song: "https://www2.cs.uic.edu/~i101/SoundFiles/CantinaBand3.wav"
},
{
key: "3",
song: "https://www2.cs.uic.edu/~i101/SoundFiles/CantinaBand3.wav"
}
]
export default function App() {
const [count, setcount] = useState(0);
const IncreaseCount = ()=>{
setcount(count + 1);
}
const renderItem = ({item, index})=>{
return(
<View style={{marginTop: 10}} >
<ChildComponent path={item.path} IncreaseCount={()=>IncreaseCount} index={index} songURL={item.song}/>
</View>
)
}
return (
<View style={{justifyContent: "center", alignItems: "center", marginTop: 200}}>
<FlatList
data={Data}
renderItem={renderItem}
extraData={count}
/>
<Text style={{marginTop: 30}}> Number of Songs Played: {count} </Text>
</View>
)
}
ChildComponent
Here I use expo-av API. Using the loadAsync() method, I Initially load the songs upon first render using useEffect hook. Then using onPress method of the button I invoke the playAsync() method of the playBackObject.
Using the setOnPlayBackStatusUpdate method, I listen for status changes. When playBackObjectStatus.didJustFinish becomes true, I call the props.IncreaseCount().
import { View, Button } from 'react-native'
import React, {useRef, useEffect} from 'react'
import { Audio } from 'expo-av';
export default function ChildComponent(props) {
const sound = useRef(new Audio.Sound());
const PlayBackStatus = useRef();
useEffect(()=>{
LoadAudio();
return ()=> sound.current.unloadAsync()
},[])
const LoadAudio = async ()=>{
PlayBackStatus.current = sound.current.loadAsync({uri: props.songURL})
.then((res)=>{
console.log(`load result : ${res}`)
})
.catch((err)=>console.log(err))
}
const PlayAuido = async ()=>{
PlayBackStatus.current = sound.current.playAsync()
.then((res)=>console.log(`result of playing: ${res}`))
.catch((err)=>console.log(`PlayAsync Failed ${err}`))
}
sound.current.setOnPlaybackStatusUpdate(
(playBackObjectStatus)=>{
console.log(`Audio Finished Playing: ${playBackObjectStatus.didJustFinish}`)
if(playBackObjectStatus.didJustFinish){
console.log(`Inside the If Condition, Did the Audio Finished Playing?: ${playBackObjectStatus .didJustFinish}`)
props.IncreaseCount();
}
}
)
return (
<View >
<Button title="Play Sound" onPress={PlayAuido} />
</View>
);
}
Problem I am facing
No matter what I do, I can't get the props.IncreaseCount to be called in App.js. Using console.log inside the if condition of setOnPlayBackStatusUpdate, I know that the props.IncreaseCount() method is being called, but the IncreaseCount() function in App.js is never called. Any help is greatly appreciated!
Here is the snack
Inside here please do this
<ChildComponent path={item.path} IncreaseCount={IncreaseCount} index={index} songURL={item.song}/>
Ive changed IncreaseCount={IncreaseCount}
DO lemme know if this helps
You have two ways to call the IncreaseCount function, in the ChildComponent
<ChildComponent IncreaseCount={IncreaseCount} path={item.path} .......
or
<ChildComponent IncreaseCount={() => IncreaseCount()} path={item.path} .......
You made a mistake while passing increaseCount prop to the ChildComponent
Here are to correct ways to do it:
return(
<View style={{marginTop: 10}} >
<ChildComponent path={item.path} IncreaseCount={IncreaseCount} index={index} songURL={item.song}/>
</View>
)
or: IncreaseCount={() => IncreaseCount()}

How to change state of one function component from another function component in React Native?

I am new to React Native and JavaScript. I want to update Text on click of button. I read other questions but mostly they are about class components. Here's my code below.
import React, { useState } from 'react';
import { View, Text, Button} from 'react-native';
const Playground = () => {
const [count, setCount] = useState(0);
return (
<View style={{ padding: 5 }}>
<Text style={{ fontSize: 26 }}>
Tap count = {count}.
</Text>
<TapButton />
</View>
);
}
const TapButton = () => {
return (
<Button
title="Hit" />
);
}
export default Playground;
Note: I know I can create Button in Playground component, But I want to know how to change state from another component or some event in another component like onPress.
Try this way
const Playground = () => {
const [count, setCount] = useState(0);
return (
<View style={{ padding: 5 }}>
...
// send `onCountPress` as prop
<TapButton count={count} onCountPress={setCount}/>
</View>
);
}
const TapButton = ({count, onCountPress}) => {
return (
<Button
...
onPress={onCountPress(count + 1)} // update here
/>
);
}
export default Playground;

React Native: Passing value from <TextInput> into a function declared outside of a component

I am currently building a component that includes a <TextInput which captures a value called userInput. I have a <TouchableOpacity> which then invokes a function which is declared outside of the component, however this particular function accepts the userInput as one of it's arguments.
I am struggling to figure out how to use the value assigned to userInput in the component's state, and pass it to myFunction. Is this possible and/or is there a better way to achieve this?
I did try moving the function inside the component, however this caused errors with the function.
Any help would be very much appreciated.
import React, {Component} from 'react';
import {Text, View} from 'react-native';
import {TextInput} from 'react-native-gesture-handler';
const myFunction = () => {
func()
.then(async user => {
const userInput = this.state.userInput;
await addToProfile(user, userInput);
})
.catch(err => {
console.error(err);
});
};
export default class Stackoverflow extends Component {
state = {
userInput: '',
};
constructor(props) {
super(props);
this.textInputComponent = React.createRef();
}
render() {
return (
<View>
<TextInput
ref={this.textInputComponent}
keyboardAppearance={'dark'}
value={this.state.userInput}
onChangeText={value => this.setState({userInput: value})}
/>
<TouchableOpacity
onPress={() => {
myFunction();
}}
/>
</View>
);
}
}
TouchableOpacity should have some child component within it to touch.
Lets take an example:
const callme= () => {
console.log("Pressed event called.....");
};
const mycomponent = () => {
return (
<TouchableItem
onPress={() => {
callme();
}}
useOpacity
>
<View style={[styles.container]}>
<Text style={[styles.mytextstyle}>Some title here</Text>
</View>
</TouchableItem>
);
};
I managed to solve the issue my moving the function declaration into the onPress() of the TouchableOpacity

TypeError: undefined is not an object (evaluating ' _this.setState')

i'm a complete beginner to React Native and i'm trying to add items to flatlist using textinput. i keep constantly getting a TypeError: undefined is not an object (evaluating'_this.setState'). i have edited the code many times and tried to research what i can do, but it still is not working properly. could someone help me and tell me what i need to change? below is my code.
thank you in advance!
import React, { useState, setState } from 'react';
import { View, Text, StyleSheet, FlatList, Alert, TouchableOpacity, TextInput } from 'react-native';
export default function FlatlistComponent({ }) {
const array = [{title: 'ONE'}, {title: 'TWO'}];
const [arrayHolder] = React.useState([]);
const [textInputHolder] = React.useState('');
const componentDidMount = () => {
setState({ arrayHolder: [...array] })
}
const joinData = () => {
array.push({ title : textInputHolder });
this.setState({ arrayHolder: [...array] });
}
const FlatListItemSeparator = () => {
return (
<View
style={{
height: 1,
width: "100%",
backgroundColor: "#607D8B",
}} />
);
}
const GetItem = (item) => {
Alert.alert(item);
}
return (
<View style={styles.MainContainer}>
<TextInput
placeholder="Enter Value Here"
onChangeText={data => this.setState({ textInputHolder: data })}
style={styles.textInputStyle}
underlineColorAndroid='transparent'
/>
<TouchableOpacity onPress={joinData} activeOpacity={0.7} style={styles.button} >
<Text style={styles.buttonText}> Add Values To FlatList </Text>
</TouchableOpacity>
<FlatList
data={arrayHolder}
width='100%'
extraData={arrayHolder}
keyExtractor={(index) => index.toString()}
ItemSeparatorComponent={FlatListItemSeparator}
renderItem={({ item }) => <Text style={styles.item} onPress={GetItem.bind(this, item.title)} > {item.title} </Text>}
/>
</View>
);
}
So I see you're trying to use functional components here.
State variables can be rewritten like this
const [arrayHolder, setArrayHolder] = useState([]);
const [textInputHolder, setTextInputHolder] = useState('');
componentDidMount is used in class components and can be rewritten like this for functional components
import React, { useState, useEffect } from 'react';
useEffect(()=>{
setArrayHolder(array)
}, [])
Function joinData can be re-written like this.
const joinData = () => {
array.push({ title : textInputHolder });
setArrayHolder(array)
}
About the text not showing up. You're using this.setState in the onChangeText event. It is a functional component and this won't work in a functional component.state variables are declared and set using the useState hook in a functional component.
You should rewrite the onChangeText event like this.
<TextInput
placeholder="Enter Value Here"
onChangeText={data => setTextInputHolder(data)}
style={styles.textInputStyle}
underlineColorAndroid='transparent'
/>
I think this'll solve your problem

Call component through function React Native

I'm developing a component to publish it in npm, but I'd like to call my component using a method instead of a tag.
Example:
myComponent.js
import React from 'react'
import { View, Text } from 'react-native'
export const showComponent = () => {
// this would be the function that I user to call my component down
}
const myComponent = (props) => {
return(
<View>
<Text>Oi</Text>
</View>
)
}
App.js
import React from 'react'
import { View, Text, TouchableOpacity } from 'react-native'
import { showComponent } from 'my-component'
const App = () => {
return(
<View>
<TouchableOpacity onPress={() => showComponent()}>
<Text>Home</Text>
</TouchableOpacity>
</View>
)
}
export defaul App
the idea is that when calling the showComponent function I show my component, and when I call, for example, the hide function, I close my component.
You can do it using a single class export:
import * as React from 'react';
export default class MyComponent extends React.Component {
state = {
isOpen: false,
};
open = () => {
this.setState({ isOpen: true });
};
close = () => {
this.setState({ isOpen: true });
};
render() {
const { isOpen } = this.state;
return !isOpen ? null : (
<View>
<Text>Oi</Text>
</View>
);
}
}
And you use it like so:
<MyComponent ref={(x) => this.myComponent = x)} />
And you open it like so:
this.myComponent.open();
I see in a comment above you want to call the component with a redux action, so you should call your redux action in that on click, but the component you want to show/hide needs to be linked to a redux state variable. Then in your jsx you'd have:
<View>
<TouchableOpacity onPress={() => showComponent()}>
<Text>Home</Text>
</TouchableOpacity>
{reduxBoolean && <MyComponent />}
</View>
import React from 'react'
import { View, Text} from 'react-native'
const example = (props) => {
return (
<View>
<Text>Hello</Text>
</View>
)
}
// props
import React from 'react'
import { View, Text} from 'react-native'
const examples = () => {
return(
<View>
<Text><example/></Text>
</View>
)
}
and print is : Hello

Categories