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>
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.
again, I need some help. I am trying to implement a shopping cart for my application.
The application has the following logic:
BarcodeScreen (params) => MenuScreen loads data from params => CheckoutScreen
The problem is, that I want to have a "Reset" button, to remove all products in the cart.
For that reason on my CheckoutScreen, there is a Reset button, which navigates to the previous screen (MenuScreen) and it needs to reset some of the state variables (the params for loading data must stay).
Here is the MenuScreen code:
function MenuScreen({ route, navigation }) {
const params = route.params;
const [products, setProducts] = useState([]);
const [loading, setLoading] = useState(true);
const [items, setItems] = useState([]);
const [length, setLength] = useState(0);
useEffect( () => {
loadMenu();
}, []);
const loadMenu = async () => {
const response = await MenuApi.getMenu(params.data);
if(!response.ok) Alert.alert(response.data.message);
setLoading(false);
setProducts(response.data.data);
}
const addItem = (item) => {
items.push(item);
setLength(items.length);
}
return (
<>
<View style={styles.activity}>
<ActivityIndicator animating={loading} size="large"/>
</View>
<FlatList
data={products}
...
/>
<View style={styles.activity}>
<Text>You have {length} products in your order</Text>
</View>
<View style={styles.activity}>
<Button title="View Basket" onPress={() => navigation.navigate("Checkout", items)}></Button>
</View>
</>
);
}
That is the CheckoutScreen code:
function CheckoutScreen({ route, navigation }) {
const products = route.params;
return (
<>
<View style={styles.activity}>
<FlatList
data={products}
...
/>
</View>
<View style={styles.activity}>
<Button title="Submit"></Button>
<Button title="Reset" onPress={() => navigation.reset({
index: 0,
items: [],
routes: [{ name: "Menu"}]
})}>
</Button>
</View>
</>
);
}
Now, when I go back to the MenuScreen, the items = 0, but I don't have the params data anymore.
MenuScreen and CheckoutScreen are two different screens each with their own state. If you want both screens to share that state and both manipulate it and for the state to persistent between them, I recommend you to use
React Redux for the job.
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 was having issues with something like this (specifically in the TextInput value attribute):
const Stuff = props => {
const [items, setItems] = useState([]);
const handleNewItem = () => {
setItems([...items, '']);
};
const handleText = (text, index) => {
items[index] = text;
setItems(items);
// this was populating correctly in console.log
// as I type, it will come out like ["somedata", "blah"....] etc...
};
return (
<>
<View style={{marginTop: 20}}>
<View>
{items.map((items, index) => {
return (
<View key={index}>
<Text>{index + 1}</Text>
// issue with setting value attribute
// Text would disappear as I type in the input field
<TextInput value={items} onChangeText={text => handleText(text, index)} />
</View>
);
})}
<TouchableOpacity onPress={e => handleNewItem(e)}>
<Text>Add item</Text>
</TouchableOpacity>
</View>
</View>
</>
);
};
I was able to get console logged out the correct values for items, but on my mobile simulator, when I type something, the text disappears.
When I removed value={items} from the TextInput component, I'm able to type in the simulator input field, without the text disappearing. I always thought we needed a value from reactjs. Do we not need this? or am I doing something wrong?
I would suggest don't directly update your state. Instead use new object to update the state like
const handleText = (text, index) => {
let newItems = [...items];
newItems[index] = text;
setItems(newItems);
};
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>
);
}