在屏幕之间传递数据的问题(重新渲染过多) [英] Porblem with passing data between screen (Too many re-renders)

查看:47
本文介绍了在屏幕之间传递数据的问题(重新渲染过多)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在屏幕之间传递数据时遇到问题.这是我输入的屏幕:

I've got a problem with passing data between screens. Here is the screen where I'm taking input:

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:

And here is the screen, where i'm passing this data (input) to add it to 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中并且它被正确发送,但是我在将它添加到

I put it in console.log and it's sent right, but i've got a problem with adding it to

const [products, setProducts]  = useState<any>([]);

(产品是我的值数组)

我尝试通过在添加后将状态更改为 false 来放置第二个 useState 以避免多次添加,但它什么也没改变,我有一个错误组件异常:重新渲染太多",也尝试使用 globalState 但它不起作用.也许有另一种更好的方法来改变输入数据的状态,谢谢你的帮助:)

I try to put a second useState to avoid multiple adding by changing state to false after adding but it changes nothing, i've got an error "Component Exception: Too many re-renders", also try to use globalState but it doesn't work. Maybe there is another and better way to change the state with input data, thanks for help :)

推荐答案

Boolean Flag

当您调用 addProduct(JSON.stringify(props.navigation.getParam('input')),true) 时,您将第二个参数 oneadd 设置为 真实.在addProduct函数中,你在检查if(didAddInput === true)之前调用setDidAddInput(oneadd);,所以它总是true 并且仍然执行无限次.

Boolean Flag

When you call addProduct(JSON.stringify(props.navigation.getParam('input')),true) you are setting the second argument oneadd to true. In the addProduct function, you call setDidAddInput(oneadd); before checking if(didAddInput === true), so it will always be true and still execute infinite times.

我们的目标是每个 input 执行一次.

Our goal is to execute once per input.

使用 boolean 标志,这就是您要做的.初始值为false.我们只在它仍然是 false 并且没有改变时添加.然后添加后,我们把它设置为true,这样就不会再运行了.

With a boolean flag, here's what you would do. The initial value is false. We only add if it is still false and has not been changed. Then after adding, we set it to true so that it will not be run again.

您不能在 setDidAddInput 之前return products 因为在 return 之后不会运行任何东西.

You cannot return products before you setDidAddInput because nothing after the return will run.

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

There is a lot that's not ideal about the above solution. The adding of a product and the accessing of all products are handled in the same function, so we are calling the function way more times than is necessary ( even though we are only adding once ).

useEffect 钩子更好.我们需要确保我们设置了正确的依赖项,以便在正确的时间运行效果.我们希望每次 input 改变时运行它.(您也可以在您的依赖项中包含 setProducts,但它不会有任何区别,因为它永远不会改变).

A useEffect hook is better. We need to make sure that we set the correct dependencies so that the effect is run at the right times. We want to run it every time that input changes. (You could also include setProducts in your dependencies, but it won't make any difference because it never changes).

让我们将 input string 定义为 useEffect 之外的变量.

Let's define the input string that we want as a variable outside of the useEffect.

addProduct 功能将存在于 useEffect 回调中.我们不返回任何东西.

The addProduct functionality will exist inside of the useEffect callback. We don't return anything.

const input: string = JSON.stringify(props.navigation.getParam('input'));

useEffect( () => {

  setProducts([...products,{id: Math.random().toString(), value: input}]);

}, [input]);

效果会自动运行,因此 products 应该使用最新数据进行更新.您的 VirtualizedList 可以直接访问 products.

The effect runs automatically so products should get updated with the latest data. Your VirtualizedList can access products directly.

这篇关于在屏幕之间传递数据的问题(重新渲染过多)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆