typescript - 在屏幕之间传递数据的问题(重新渲染过多)
问题描述
我在屏幕之间传递数据时遇到问题。这是我正在输入的屏幕:
import React, {useState} from 'react'
import {View, TextInput, Button, StyleSheet, TouchableWithoutFeedback, Keyboard} from 'react-native'
import { useGlobal } from 'reactn';
import Card from '../components/Card'
import colors from '../constants/colors';
type Props={
navigation:any
}
const AddingScreen = (props:Props) =>{
let annmountAndProductToSend:any;
const [enteredProduct, setEnteredProduct] = useState<string>('');
const [amount, setAmount] = useState<any>('');
function enteredProductHandler(enteredText:string):void
{
setEnteredProduct(enteredText);
}
function amountHandler(enteredText:any):void
{
let amountAndProduct;
const amm = parseInt(enteredText);
if(isNaN(enteredText) || enteredText > 1)
{
setAmount(enteredText);
amountAndProduct = enteredText + ' ' + enteredProduct;
annmountAndProductToSend = amountAndProduct;
}
else setAmount('')
}
function confirmProduct()
{
props.navigation.navigate('Main',{input:enteredProduct});
setEnteredProduct('');
setAmount('');
}
function returnToMainScreen()
{
props.navigation.navigate('Main')
}
return(
<TouchableWithoutFeedback onPress = {() => {Keyboard.dismiss();}}>
<View style = {styles.inputContainer}>
<Card style = {styles.screen} >
<TextInput blurOnSubmit autoCapitalize="none"
placeholder="Nazwa przedmiotu"
style={styles.input}
onChangeText={enteredProductHandler} //1.onChangeText pobiera wpisany text i wysyła do goalInputHandler
value={enteredProduct}
/>
<TextInput keyboardType = "number-pad"
placeholder="Ilość"
style={styles.input}
onChangeText={amountHandler} //1.onChangeText pobiera wpisany text i wysyła do goalInputHandler
value={amount}
/>
<View style = {styles.buttonContainer}>
<View style = {styles.button}>
<Button color = {colors.accent} title = 'Dodaj' onPress = {confirmProduct}/>
</View>
<View style = {styles.button}>
<Button title = 'Wyjdź' color = {colors.accent} onPress={returnToMainScreen}/>
</View>
</View>
</Card>
</View>
</TouchableWithoutFeedback>
);
};
const styles = StyleSheet.create({
screen:
{
justifyContent:'center',
alignItems:'center',
},
inputContainer:{
flex: 0.5,
justifyContent:'center',
alignItems:'center'
},
input:{
height:30,
borderBottomColor: 'grey',
borderBottomWidth: 1,
marginVertical: 13,
},
buttonContainer:{
flexDirection:'row',
alignItems: 'center',
justifyContent: 'space-between' ,
width: '60%'
},
button:{
width:'40%',
}
});
export default AddingScreen;
这是屏幕,我正在传递此数据(输入)以将其添加到 VirtualizedList:
import { StatusBar } from 'expo-status-bar';
import React, {useState, useContext} from 'react';
import {
StyleSheet,
View,
Button,
VirtualizedList,
Alert,
} from 'react-native';
import GoalItem from'../components/Goalitem';
import Header from '../components/Header';
import colors from '../constants/colors';
type Props={
navigation:any
}
//setProducts([...products,{id: Math.random().toString(), value: props.navigation.getParam('input')}]);
const MainScreen = (props:Props) =>{
const [products, setProducts] = useState<any>([]);
const [didAddInput, setDidAddInput] = useState<boolean>(false);
const [amont, setAmount] = useState<any>([]);
function addProduct(input:string,oneadd:boolean){
setDidAddInput(oneadd);
if(didAddInput === true)
{
setProducts([...products,{id: Math.random().toString(), value: input}]);
return products;
}
setDidAddInput(false)
};
function removeGoalHandler(goalId:any):void
{
setProducts((courseGoals: any[]) =>
{
return courseGoals.filter((goal:any) => goal.id !== goalId);
});
};
function deleteListAlert():void
{
if(products.length >0)
{
Alert.alert(
'Lista zostanie wyczyszczona!',
'Czy aby na pewno chcesz wyczyścić liste?',
[{text: 'Tak', style: 'destructive', onPress: deleteList},
{text: 'Nie', style: 'cancel'}]);
}
else{
Alert.alert(
'Lista jest pusta.',
'W liście nie ma żadnych przedmiotów.',
[{text: 'Powrót', style: 'cancel'}]);
}
}
function deleteList()
{
setProducts('')
}
function count():number
{
return 50;
}
return (
<View style = {styles.screen}>
<Header title="Lista zakupów"/>
<VirtualizedList
keyExtractor={(item:any, index) => item.id}
//data ={addProduct(value)}
getItem = {addProduct(JSON.stringify(props.navigation.getParam('input')),true)}
getItemCount = {count}
renderItem ={itemData => (
<GoalItem
id = {itemData.item.id}
onDelete = {removeGoalHandler}
title = {itemData.item.value}
/>
)}
/>
<View style = {styles.buttonPosition}>
<View style = {styles.button1}>
<Button color = {colors.accent} title = "WYCZYŚĆ" onPress={deleteListAlert}/>
</View>
<View style = {styles.button}>
<Button color = {colors.accent} title="+" onPress = {() => {
props.navigation.navigate('Adding')
}}/>
</View>
</View>
</View>
);
}
const styles = StyleSheet.create({
screen:{
flex:1,
backgroundColor: 'white',
},
button:{
width: 40,
},
button1:{
width: 90,
},
buttonPosition:{
padding:15,
alignItems: 'stretch',
justifyContent: 'space-between',
flexDirection:'row',
backgroundColor: colors.primary,
},
});
export default MainScreen;
所以我的数据在这里:
getItem = {addProduct(JSON.stringify(props.navigation.getParam('input')),true)}
我把它放在 console.log 中,它发送正确,但我在添加它时遇到了问题
const [products, setProducts] = useState<any>([]);
(产品是我的价值观数组)
我尝试通过在添加后将状态更改为 false 来放置第二个 useState 以避免多次添加,但它没有任何改变,我有一个错误“组件异常:重新渲染太多”,也尝试使用 globalState 但它没有工作。也许还有另一种更好的方法来改变输入数据的状态,谢谢你的帮助:)
解决方案
布尔标志
当您打电话时,addProduct(JSON.stringify(props.navigation.getParam('input')),true)
您将第二个参数设置oneadd
为true
. 在addProduct
函数中,您setDidAddInput(oneadd);
在检查之前调用if(didAddInput === true)
,因此它将始终true
并且仍然执行无限次。
我们的目标是每次执行一次input
。
有了boolean
旗帜,这就是你要做的。初始值为false
。我们仅在它仍然false
存在且未更改时添加。然后添加后,我们将其设置为true
,使其不会再次运行。
你不能return products
在你之前,setDidAddInput
因为意志之后什么都没有return
。
function addProduct(input:string) {
// only add if not already added
if( didAddInput === false ) {
setProducts([...products,{id: Math.random().toString(), value: input}]);
// prevent adding again
setDidAddInput(false);
}
// always return products
return products;
};
使用效果
上述解决方案有很多不理想的地方。产品的添加和所有产品的访问都在同一个函数中处理,因此我们调用该函数的次数超出了必要的次数(即使我们只添加了一次)。
一个useEffect
钩子更好。我们需要确保设置正确的依赖关系,以便在正确的时间运行效果。我们希望在每次input
发生变化时运行它。(您也可以包含setProducts
在您的依赖项中,但它不会有任何区别,因为它永远不会改变)。
让我们将input
string
我们想要的 定义为 之外的变量useEffect
。
addProduct 功能将存在于useEffect
回调中。我们不返回任何东西。
const input: string = JSON.stringify(props.navigation.getParam('input'));
useEffect( () => {
setProducts([...products,{id: Math.random().toString(), value: input}]);
}, [input]);
效果会自动运行,因此products
应该使用最新数据进行更新。您VirtualizedList
可以products
直接访问。
推荐阅读
- javascript - call rest api and display result as searched for
- regex - 使用正则表达式验证用户代理
- node.js - NodeJs / Express 如何加载验证中间件
- javascript - Javascript 可以禁用/启用按钮,但不能禁用单选按钮或文本区域
- python - scipy kstest,用于 scipy 对数正态分布
- javascript - Javascript JSON 名称是唯一的 ID
- php - 如何获取数组中每个数字的阶乘值?
- javascript - 使用 style-loader 访问 webpack 插件中生成的 css
- sql-server - 使用查询结果更新表中的列
- c# - 使用 C# 为 cmd 转义反斜杠