Lets say I have my main component, where if the type of {data} is "textSingles" I render the TextSingle component:
const Information = (props) => {
const data = props.data
return (
<View>
<Text>Information</Text>
{data.type == "textsingle" &
<TextSingle data={data}/>
}
</View>
)}
Here is my TextSingle component":
const TextSingle = (props) => {
const [item, setItem] = useState(props.data)
const [text, setText] = useState('')
return (
<View style={[styles.card, styles.shadowProp]}>
{/* card label */}
<View style={styles.cardHeaderTextContainer}>
<Text style={styles.cardHeaderText}>{item.label}</Text>
</View>
{/* input container */}
<View style={styles.inputContainer}>
<TextInput
style={styles.textInput}
placeholder='Enter Text'
onChangeText={text => setText(text)}
autoCapitalize='none'
placeholderTextColor='#949494'
></TextInput>
</View>
</View>
)
}
Within my Information component I am rendering TextSingle. With in TexSingle I have a text input, and that value sets the "text" var.
In this case I want to send the answer to firebase.
How do I get the value of that text input in Information component?
use can use hook names useimperativehandle for use child functions in parent class. if you don't want to and you can pass function from parent here's it
in your information component
const Information = (props) => {
const data = props.data
const [text, setText] = useState('')
return (
<View>
<Text>Information</Text>
{data.type == "textsingle" &
<TextSingle data={data} onChangeText={text => setText(text)}/>
}
</View>
)}
and in your textsingle
const TextSingle = (props) => {
const [item, setItem] = useState(props.data)
return (
<View style={[styles.card, styles.shadowProp]}>
{/* card label */}
<View style={styles.cardHeaderTextContainer}>
<Text style={styles.cardHeaderText}>{item.label}</Text>
</View>
{/* input container */}
<View style={styles.inputContainer}>
<TextInput
style={styles.textInput}
placeholder='Enter Text'
onChangeText={props.onChangeText}
autoCapitalize='none'
placeholderTextColor='#949494'
></TextInput>
</View>
</View>
)
}
Related
I am starting in React Native and I would like to know how I can maintain the data that is in the state of a child component.
I am making an application that generates a certain amount of tables. Inside these tables, I have a menu, and inside this menu, I have components that are in charge of the logic to be able to make the sum of the dishes that were served, and how much is the whole. But when I return to the page where my tables are, all the results of my accounts that were in each table, were deleted.
This is the component that is responsible for creating each table
export default function Cuentas() {
const { mesa, handleClick } = useContext(MesaContext);
return (
<View style={style.container}>
<View style={style.bottonContainer}>
<TouchableOpacity style={style.FAB} onPress={handleClick}>
<Text style={style.FabText}> Nueva mesa</Text>
</TouchableOpacity>
</View>
<FlatList
data={mesa}
keyExtractor={(mesa) => String(mesa.id)}
renderItem={({ item }) => <Mesa mesas={item} />}
horizontal={false}
style={style.FlatList}
showsVerticalScrollIndicator={false}
/>
</View>
);
}
This is the Component that renders a component that is in charge of rendering all the decks
export default function CuentaMesa(props) {
const {
route: { params },
navigation,
} = props;
const { mesa } = useContext(MesaContext);
return (
<View style={style.container}>
<Text style={style.TitleMesa}>{params.name}</Text>
<Platos />
</View>
);
}
This is where all the dishes are rendered
export default function Platos() {
const [platos, setPlatos] = useState(platosService);
const [total, setTotal] = useState(null);
return (
<View style={style.container}>
<View style={style.Text}>
{platos.map(plato => {
return (
<View key={plato.id} style={style.platosContainer}>
<View style={style.platosView}>
<Text style={style.platoTitle}>{plato.name}</Text>
<Text style={style.platoPrice}>${plato.price}</Text>
</View>
<View>
<Plato price={plato.price} />
</View>
</View>
);
})}
</View>
</View>
);
This is where the inputs are, which are used to do all the logic, I want the data that is here (The result of each operation that was done with the input) to be saved, so that when leaving the array, where are they the tables and when you go back in, that information is there
export default function Plato(props) {
const [input, setInput] = useState(null)
const [suma, setSuma] = useState(null)
const { price } = props
console.log(price);
console.log(input)
const sumaPrecios = () => {
setSuma(Number(input) * price)
}
return (
<View>
<Text>{price}</Text>
<Text>Suma:{suma}</Text>
<TextInput placeholder='Cantidad' style={style.input} value={input} onChangeText={setInput} />
<Button title='Total' onPress={sumaPrecios} />
</View>
)
}
Thank you very much in advance for your help.
I would like to change the state from my value propreties, but my variable is a JSON.
import React, { useEffect, useState, useForm } from 'react';
import {
Button,
View,
Text,
FlatList,
TouchableOpacity,
ActivityIndicator,
Input,
} from 'react-native';
import { TextInput, Alert, Card, Title } from 'react-native-paper';
export default function Cadastrar({ route, titleMessage, messageField }) {
//pega o id dos parametros de rota, exportado no arquivo MESSAGECARD.JS na ação de clicar
const { id } = route.params;
const [DADOS, setData] = useState([]);
const getCardsMessages = async () => {
const response = await fetch(
`https://back-end.herokuapp.com/${id}`
);
const jsonObj = await response.json();
setData(jsonObj);
};
useEffect(() => {
getCardsMessages();
}, []);
const [titleMessage2, onChangeText] = useState("TESTE EVENT");
const [selectedId, setSelectedId] = useState(null);
const [search, setSearch] = useState('');
const updateSearch = (text) => {
setSearch(text);
};
return (
<View style={{ flex: 1, padding: 24 }}>
<FlatList
data={DADOS}
keyExtractor={(item) => item.id}
renderItem={({ item }) => (
<View>
<TextInput
value={"ID: "+item.id}
extraData={selectedId}
onPress={() => setSelectedId()}>
</TextInput>
<TextInput
placeholder="Titulo"
value={item.titleMessage}
onChangeText={(text) => updateSearch(text)}
></TextInput>
<TextInput value={item.messageField}>
</TextInput>
<TextInput
placeholder="Titulo"
value={titleMessage2}
onChangeText={onChangeText}>
</TextInput>
<Text style={{ margin: 10, padding: 10 }}>
<Button title="Atualizar Post" />
</Text>
</View>
)}
/>
</View>
);
}
I have trying this, but how can i get the value of these props which come from a json: value={item.titleMessage}
and update the:
const [search, setSearch] = useState('');
if goes this way it works:
value={search}
Anything will help, i starting my studies in react! Thanks a lot
Instead of calling updateSearch call your setSearch directly.
<TextInput
placeholder="Titulo"
value={search}
onChangeText={text => setSearch(text)}
/>
Well, at the start I didn't understood your question and I refactored your code to a map as we normally do in react thinking that it was what you want... Just to don't just delete it i'll keep it there to you, it wont be used to your question but you can refactor to your response of the search :) Also, its better to call your hooks in lower case. So change DADOS to dados.
export default function Cadastrar({ route, titleMessage, messageField }) {
...
if (DADOS[0]?.id != undefined) {
return (
<View style={{ flex: 1, padding: 24 }}>
{
DADOS.map(dado => {
return (
<View key={dado.id}>
<TextInput
value={"ID: " + dado.id}
extraData={selectedId}
onPress={() => setSelectedId()}
/>
<TextInput
placeholder="Titulo"
value={dado.titleMessage}
onChangeText={(text) => updateSearch(text)}
/>
<TextInput
value={dado.messageField}
/>
<Text style={{ margin: 10, padding: 10 }}>
<Button title="Atualizar Post" />
</Text>
</View>
)
})
}
</View>
);
} else {
return (
<div>DADOS não tem nada</div>
)
}
}
What I do there is, first check if the hook has data, if not will return a div saying that don't have any data, there you can put whatever you want. Then, if found data, I return your View with a map of the data inside.
To do the map you open a {}, that way you can write javascript inside the html, then you put your data to map, and for each data you return the component that you specify in the return.
Since you're returning many components you need some unique value to distinguish one to another, you do this by passing a unique key value to the element that wraps everything, in your case, other view. And since the id is a unique value, you pass the id in the key.
The rest is just put the values that you need to show in the components, beign it as props or writting the value inside the element.
I removed the titleMessage2 element since I assumed that it will be the 2nd id of your array of jsons.
well you can create a state variable to select one and other state variable to alternatives
const [search, setSearch] = useState(yourJson);
const [selected, setSelected] = useState('');
and now in your function updateSearch
const updateSearch =(newValue)=>{
setSelected(newValue)
}
and in the ui side you need to modify this
<TextInput
placeholder="title"
value={selected}
onChangeText={(text) => updateSearch(text)}
></TextInput>
I'm trying to show a FlatList, which is initially hidden, when the user clicks on a TextInput, but I'm getting an error saying that there are too many re-renders, take a look at the code:
const [state, setState] = useState ({
...
showFlatList: false,
})
return (
<ImageBackground source = {enterInfoBackGroundImage} style = {styles.container}>
<SafeAreaView>
<View style = {styles.backgroundArea}>
<TextInput style = {styles.inputText}
onFocus = {setState({showFlatList: true})}
autoCapitalize='characters'
placeholder = {'MAKE'}
placeholderTextColor = {'#B2B2B2'}
onChangeText = {text => setState({...state, companyName: text })}
value = {state.make}
/>
{state.showFlatList && <FlatList
style = {styles.tableView}
data = {make}
keyExtractor = {(item) => item.id}
renderItem = {({ item }) => (
<TouchableOpacity style = {styles.tableViewItem} onPress = {() => {
console.log(item.make, item.id)
}}>
<Text style = {styles.searchBarText}>{item.make}</Text>
</TouchableOpacity>
)}
/>}
</View>
</SafeAreaView>
</ImageBackground>
);
I'm only getting this error when I put {setState({showFlatList: true})} on onFocus, but when I put that inside onPress inside the TouchableOpacity, it worked, any kind of feedback is appreciated! :)
The problem is how you call setState on the onFocus property of your TextInput.
It should look more like this:
<TextInput
onFocus={() => {
setState({showFlatList: true});
}}
// ...
/>
So the same way you handled your TouchableOpacity's onPress.
I have a component that renders the input field, I want to pass the data to the next page when user clicks on "next" button in the header. What is the best practice for doing so? How do I expose this into Page.navigationOptions?
Or is it best to just set up redux for these types of things?
const Page = () => {
const [desc, getDesc] = useState('');
return (
<View style={styles.inputFieldDescContainer}>
<TextInput
multiline
placeholder='Write a description...'
onChangeText={(text) => getDesc(text)}
value={desc}
/>
</View>
);
};
// How do I pass desc properties down into navigationOptions?
Page.navigationOptions = (navData) => {
return {
headerTitle: 'Page,
headerRight: (
<HeaderButtons HeaderButtonComponent={HeaderButton}>
<Item
title='Next'
onPress={() => {
navData.navigation.navigate('NextPage', {data: navData});
}}
/>
</HeaderButtons>
),
headerBackTitle: null
};
};
/* NextPage.js */
const NextPage = (props) => {
console.log('enter props data', props.navigation.getParam('data'));
console.log('enter props navigation', props.navigation);
const [valueText, setValueText] = useState();
return (
<View>
<TextInput onChangeText={(text) => setValueText(text)} value={valueText}/>
<TouchableOpacity><Text>Create your workout</Text></TouchableOpacity>
</View>
);
;}
Sharing state and props between component and options is possible in React Navigation 5 https://blog.expo.io/announcing-react-navigation-5-0-bd9e5d45569e
In React Navigation 4, you can use params to store the value to be able to share it:
const Page = ({ navigation }) => {
const desc = navigation.getParam('description', '');
return (
<View style={styles.inputFieldDescContainer}>
<TextInput
multiline
placeholder='Write a description...'
onChangeText={(text) => navigation.setParams({ description: text )}
value={desc}
/>
</View>
);
}
I use a RootForm as the basic template for form page. There is one field associated with location autocomplete, so I wrap the native autocomplete of react-native and use it in that field. However, the autocomplete dropdown list is blocked by other fields in the form which are rendered behind it. I try to search online but no useful materials. Using modal or zIndex is not the solution here. How could I make the dropdown list on the top of other components even if it renders earlier than other components?
The following two snippets are my rootform and autocomplete render functions.
render() {
const { input } = this.state;
const cities = this.state.cities;
return (
<View style={styles.container}>
<Autocomplete
autoCapitalize="none"
autoCorrect={false}
containerStyle={styles.autocompleteContainer}
data={cities}
defaultValue={input}
onChangeText={text => this.setState({ input: text })}
placeholder="Enter Location"
renderItem={({ cityName, cityId }) => (
<TouchableOpacity style={styles.listStyle} onPress={() => this.setState({ input: cityName, cities: [] })}>
<Text style={styles.itemText}>
{cityName}
</Text>
</TouchableOpacity>
)}
/>
</View>
);
}
render() {
const data = this.props.data;
let fields = [];
let onPress = null;
Object.keys(data).forEach((key, index) => {
let options = data[key].options ?
data[key].options : null
if ("type" in data[key]) {
fields.push(
<View style={styles.formField} key={key}>
<Text style={styles.text}>{data[key].label}</Text>
<AutoComplete />
</View>
)
} else {
let custom = [styles.formField];
if (options) {
fields.push(
<View style={custom} key={key}>
<Text style={styles.text}>{data[key].label}</Text>
<TextInput value={data[key].value} style={styles.input}
readOnly
{...options} />
</View>
)
} else {
fields.push(
<View style={custom} key={key}>
<Text style={styles.text}>{data[key].label}</Text>
<TextInput value={data[key].value} style={styles.input}
onChangeText={(text) => this.props.onFieldChange(key, text)}
{...options} />
</View>
);
}
}
})
return (
<KeyboardAwareScrollView style={styles.container}>
{fields}
</KeyboardAwareScrollView>
)
}
You can just change your style.container to have a higher zIndex than whatever is appearing on top of it. However this will have the other items in the form appear behind the area reserved for the dropdown list, and render them unselectable.
If you want items underneath the Autocomplete component's area to still be interactive/selectable, you can use React.useState in order to have a dynamic zIndex property on your component.
const [componentZIndex, setComponentZIndex] = React.useState(1);
You will want your components behind the area reserved for the list to have a zIndex higher than 2 so that they are interactive.
Then you'll want to render your own input component so that you have access to the onFocus property. Luckily, the library you are using allows you to do this:
renderTextInput={() => (
<View style={styles.input}>
<TextInput
onFocus={() => setComponentZIndex(999)}
value={value}
/>
</View>
)}
This will bring the list to the top whenever the user is using the autocomplete component. The last thing to do is to make sure that you push it to the back once the user is no longer using it.
React.useEffect(() => {
Keyboard.addListener('keyboardDidHide', _keyboardDidHide);
return () => {
Keyboard.removeListener('keyboardDidHide', _keyboardDidHide);
};
}, []);
const _keyboardDidHide = () => {
setComponentZIndex(1)
};