如何在react-native的父组件中显示一个值?

IT技术 reactjs react-native
2021-05-01 01:17:06

我有一个页面显示硬币列表。从那里我导航到另一个组件并将硬币名称作为参数传递。

从第二页开始,我根据params中收到的币名过滤了所有订单。这里,我计算了平均值。如何将其传递回父页面,以便我可以看到每个硬币旁边的订单平均值?

我的代码流

//屏幕1代码:

import React, { useEffect, useState } from "react";
import {
  FlatList,
  Keyboard,
  Text,
  TextInput,
  TouchableOpacity,
  View,
  StyleSheet,
  TouchableWithoutFeedback,
} from "react-native";
import { SwipeListView } from "react-native-swipe-list-view";
import styles from "./styles";
import { firebase } from "../../firebase/config";

export default function CoinCreate(props) {
  const [coinText, setCoinText] = useState("");
  const [coins, setCoins] = useState([]);

  const coinRef = firebase.firestore().collection("coins");
  const userID = props.extraData.id;

  useEffect(() => {
    coinRef
      .where("authorID", "==", userID)
      .orderBy("createdAt", "desc")
      .onSnapshot(
        (querySnapshot) => {
          const newCoins = [];
          querySnapshot.forEach((doc) => {
            const coin = doc.data();
            coin.id = doc.id;
            newCoins.push(coin);
          });
          setCoins(newCoins);
        },
        (error) => {
          console.log(error);
        }
      );
  }, []);

  const onAddButtonPress = () => {
    if (coinText && coinText.length > 0) {
      const timestamp = firebase.firestore.FieldValue.serverTimestamp();
      const data = {
        text: coinText,
        authorID: userID,
        createdAt: timestamp,
      };
      coinRef
        .add(data)
        .then((_doc) => {
          setCoinText("");
          Keyboard.dismiss();
        })
        .catch((error) => {
          alert(error);
        });
    }
  };
  const renderCoin = ({ item, index }) => {
    return (
      <View style={styles1.rowFront}>
        <TouchableWithoutFeedback
          onPress={() =>
            props.navigation.navigate("Orders", {
              coin: item.text,
              userID: userID,
            })
          }
        >
          <Text>
            {index}. {item.text}
          </Text>
        </TouchableWithoutFeedback>
      </View>
    );
  };

  return (
    <View style={styles.container}>
      <View style={styles.formContainer}>
        <TextInput
          style={styles.input}
          placeholder="Add new coin"
          placeholderTextColor="#aaaaaa"
          onChangeText={(text) => setCoinText(text)}
          value={coinText}
          underlineColorAndroid="transparent"
          autoCapitalize="none"
        />
        <TouchableOpacity style={styles.button} onPress={onAddButtonPress}>
          <Text style={styles.buttonText}>Add</Text>
        </TouchableOpacity>
      </View>
      {coins && (
        <SwipeListView
          data={coins}
          keyExtractor={(item) => item.id}
          renderItem={renderCoin}
          removeClippedSubviews={true}
        />
      )}
    </View>
  );
}

const styles1 = StyleSheet.create({
  rowFront: {
    alignItems: "center",
    backgroundColor: "#FFF",
    borderBottomWidth: 0.25,
    justifyContent: "center",
    height: 50,
  },
  rowBack: {
    alignItems: "center",
    backgroundColor: "#DDD",
    flex: 1,
    flexDirection: "row",
    justifyContent: "space-between",
    paddingLeft: 15,
  },
  backRightBtn: {
    alignItems: "center",
    bottom: 0,
    justifyContent: "center",
    position: "absolute",
    top: 0,
    width: 75,
    backgroundColor: "red",
    right: 0,
  },
});

//屏幕2代码:

import React, { useEffect, useState } from "react";
import {
  FlatList,
  Keyboard,
  Text,
  TextInput,
  TouchableOpacity,
  View,
  StyleSheet,
} from "react-native";
import { Avatar, Button, Card, Title, Paragraph } from "react-native-paper";
import { SwipeListView } from "react-native-swipe-list-view";
import styles from "./styles";
import { firebase } from "../../firebase/config";
import { Icon } from "react-native-elements";
import { createIconSetFromFontello } from "@expo/vector-icons";

export default function OrderList(props) {
  const LeftContent = (props) => <Avatar.Icon {...props} icon="folder" />;

  const [orderText, setOrderText] = useState("");
  const [orders, setOrders] = useState([]);

  const orderRef = firebase.firestore().collection("orders");
  const userID = props.route.params.userID;
  const coin = props.route.params.coin;

  //averageValue = (totalCost / totalCount).toString();
  const [averageValue, setAverageValue] = useState("");

  useEffect(() => {
    orderRef
      .where("authorID", "==", userID)
      .where("name", "==", coin)
      .orderBy("createdAt")
      .onSnapshot(
        (querySnapshot) => {
          const newOrders = [];
          querySnapshot.forEach((doc) => {
            const order = doc.data();
            order.id = doc.id;
            newOrders.push(order);
          });
          setOrders(newOrders);
        },
        (error) => {
          console.log(error);
        }
      );
  }, []);

  useEffect(() => {
    //calculate and set anything like totalCost, averageValue, etc here
    console.log("---came to orders effect---");
    //console.log(orders);
    let totalCost = 0;
    let totalCount = 0;
    orders.forEach((item, index) => {
      console.log(item);
      console.log(index);
      totalCost += parseFloat(item.amount);
      totalCount += parseFloat(item.count);
    });
    setAverageValue((totalCost / totalCount).toString());
  }, [orders]);
  /*
  useEffect(() => {
    let avg = (parseFloat(totalCost) / parseFloat(totalCount)).toString();
    console.log("Avg:" + avg);
    setAverageValue(avg);
  }, [totalCount, totalCost]);
*/
  const onAddButtonPress = () => {
    props.navigation.navigate("CreateOrder", {
      coin: coin,
      userID: userID,
      orderRef,
    });
  };

  const renderOrder = ({ item, index }) => {
    //console.log("----------------------");
    //console.log(item.createdAt.toDate().toString());
    //console.log("----------------------");
    //setTotalCost(parseFloat(totalCost) + parseFloat(item.price));
    //setTotalCount(parseFloat(totalCount) + parseFloat(item.count));
    //totalCost = parseFloat(totalCost) + parseFloat(item.price);
    //totalCount = parseFloat(totalCount) + parseFloat(item.count);

    //console.log(totalCost);
    //console.log(totalCount);

    return (
      <View style={styles1.rowFront}>
        <Text>
          {index}. {item.price} {item.amount} {item.count}
          {"\n" + item.createdAt.toDate().toString()}
        </Text>

        <Icon name={"flight-takeoff"} />
      </View>
    );
  };

  return (
    <View style={styles.container}>
      <TouchableOpacity style={styles.button} onPress={onAddButtonPress}>
        <Text style={styles.buttonText}>Click here to create new order..</Text>
      </TouchableOpacity>
      {orders.length === 0 && (
        <Text>Please order some coins in currency: {coin}</Text>
      )}
      {orders && orders.length > 0 && (
        <>
          <Text>Average Value: {averageValue}</Text>
          <SwipeListView
            data={orders}
            keyExtractor={(item) => item.id}
            renderItem={renderOrder}
            removeClippedSubviews={true}
          />
        </>
      )}
    </View>
  );
}

const styles1 = StyleSheet.create({
  rowFront: {
    alignItems: "center",
    backgroundColor: "#FFF",
    borderBottomWidth: 0.25,
    justifyContent: "center",
    height: 50,
  },
  rowBack: {
    alignItems: "center",
    backgroundColor: "#DDD",
    flex: 1,
    flexDirection: "row",
    justifyContent: "space-between",
    paddingLeft: 15,
  },
  backRightBtn: {
    alignItems: "center",
    bottom: 0,
    justifyContent: "center",
    position: "absolute",
    top: 0,
    width: 75,
    backgroundColor: "red",
    right: 0,
  },
});

为了简化这个过程,我在一个单独的文件中创建了一个带有 orderListData(coin,userID) 的普通函数(不是react组件)并导入它并从屏幕 1 调用该函数,但得到错误

TypeError: (0, _OrderListData.orderListData) is not a function. (In '(0, _OrderListData.orderListData)("ada", "nMOpBupcptZF8YlxiJYFX7vPMtC2")', '(0, _OrderListData.orderListData)' is undefined)

我的代码:

订单列表数据.js

import { firebase } from "../../firebase/config";

export default function orderListData(coin, userID) {
  let orders = [];
  const orderRef = firebase.firestore().collection("orders");
  //const userID = props.route.params.userID;
  //const coin = props.route.params.coin;
  let totalCost = 0;
  let totalCount = 0;
  let averagePrice = 0;

  orderRef
    .where("authorID", "==", userID)
    .where("name", "==", coin)
    .orderBy("createdAt")
    .onSnapshot(
      (querySnapshot) => {
        querySnapshot.forEach((doc) => {
          const order = doc.data();
          order.id = doc.id;
          orders.push(order);
        });
      },
      (error) => {
        console.log(error);
      }
    );

  orders.forEach((item, index) => {
    totalCost += parseFloat(item.amount);
    totalCount += parseFloat(item.count);
  });
  averagePrice = totalCost / totalCount;

  return {
    averagePrice,
    totalCost,
    totalCount,
  };
}

以及修改后的屏幕 1:

import React, { useEffect, useState } from "react";
import {
  FlatList,
  Keyboard,
  Text,
  TextInput,
  TouchableOpacity,
  View,
  StyleSheet,
  TouchableWithoutFeedback,
} from "react-native";
import { SwipeListView } from "react-native-swipe-list-view";
import styles from "./styles";
import { firebase } from "../../firebase/config";
import { orderListData } from "./OrderListData";

export default function CoinCreate(props) {
  console.log("testing");
  console.log(orderListData("ada", "nMOpBupcptZF8YlxiJYFX7vPMtC2"));

  const [coinText, setCoinText] = useState("");
  const [coins, setCoins] = useState([]);

  const coinRef = firebase.firestore().collection("coins");
  const userID = props.extraData.id;

  useEffect(() => {
    coinRef
      .where("authorID", "==", userID)
      .orderBy("createdAt", "desc")
      .onSnapshot(
        (querySnapshot) => {
          const newCoins = [];
          querySnapshot.forEach((doc) => {
            const coin = doc.data();
            coin.id = doc.id;
            newCoins.push(coin);
          });
          setCoins(newCoins);
        },
        (error) => {
          console.log(error);
        }
      );
  }, []);

  const onAddButtonPress = () => {
    if (coinText && coinText.length > 0) {
      const timestamp = firebase.firestore.FieldValue.serverTimestamp();
      const data = {
        text: coinText,
        authorID: userID,
        createdAt: timestamp,
      };
      coinRef
        .add(data)
        .then((_doc) => {
          setCoinText("");
          Keyboard.dismiss();
        })
        .catch((error) => {
          alert(error);
        });
    }
  };
  const renderCoin = ({ item, index }) => {
    let { averagePrice, totalCost, totalCount } = orderListData(
      item.text,
      userID
    );
    return (
      <View style={styles1.rowFront}>
        <TouchableWithoutFeedback
          onPress={() =>
            props.navigation.navigate("Orders", {
              coin: item.text,
              userID: userID,
            })
          }
        >
          <Text>
            {index}. {item.text} {averagePrice}
          </Text>
        </TouchableWithoutFeedback>
      </View>
    );
  };

  return (
    <View style={styles.container}>
      <View style={styles.formContainer}>
        <TextInput
          style={styles.input}
          placeholder="Add new coin"
          placeholderTextColor="#aaaaaa"
          onChangeText={(text) => setCoinText(text)}
          value={coinText}
          underlineColorAndroid="transparent"
          autoCapitalize="none"
        />
        <TouchableOpacity style={styles.button} onPress={onAddButtonPress}>
          <Text style={styles.buttonText}>Add</Text>
        </TouchableOpacity>
      </View>
      {coins && (
        <SwipeListView
          data={coins}
          keyExtractor={(item) => item.id}
          renderItem={renderCoin}
          removeClippedSubviews={true}
        />
      )}
    </View>
  );
}

const styles1 = StyleSheet.create({
  rowFront: {
    alignItems: "center",
    backgroundColor: "#FFF",
    borderBottomWidth: 0.25,
    justifyContent: "center",
    height: 50,
  },
  rowBack: {
    alignItems: "center",
    backgroundColor: "#DDD",
    flex: 1,
    flexDirection: "row",
    justifyContent: "space-between",
    paddingLeft: 15,
  },
  backRightBtn: {
    alignItems: "center",
    bottom: 0,
    justifyContent: "center",
    position: "absolute",
    top: 0,
    width: 75,
    backgroundColor: "red",
    right: 0,
  },
});

请对此提出任何建议。

1个回答

有多种方法可以解决此问题,您的要求是根据另一个屏幕更新一个屏幕,因此您可以考虑为此使用状态管理,但在您的情况下,您有返回的触发器,因此请使用导航的功能图书馆做到这一点。

因此,我将使用发送数组的简单场景在此处放置一个工作示例

假设您有一个主屏幕,从这里我们转到 CreateOrder 屏幕,它将通过 navigation.navigate 发送数据执行此屏幕(导航功能将导航到现有屏幕或推送新屏幕,因此您将在此处返回)。

function HomeScreen({ navigation, route }) {
  React.useEffect(() => {
    if (route.params?.orders) {

    }
  }, [route.params?.orders]);

  return (
    <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
      <Button
        title="Create post"
        onPress={() => navigation.navigate('CreateOrder')}
      />
      <Text style={{ margin: 10 }}>Post: {route.params?.orders?.length}</Text>
    </View>
  );
}

如果参数更新并使用路由props,您可以使用 useEffect 进行更新。

第二个屏幕将覆盖后退按钮,并且还有一个按钮可以返回。这里我们通过 navigation.navigate 发送 orders 数组

function CreateOrdersScreen({ navigation, route }) {
  const [orders, setOrders] = React.useState('');

  React.useLayoutEffect(() => {
    navigation.setOptions({
      headerLeft: (props) => (
        <HeaderBackButton
          {...props}
          onPress={() => {
            navigation.navigate('Home', { orders });
          }}
        />
      ),
    });
  }, [navigation, orders]);

  return (
    <>
      <Text>{orders.length}</Text>
      <Button
        title="Add"
        onPress={() => {
          setOrders([...orders, 1]);
        }}
      />
      <Button
        title="Done"
        onPress={() => {
          // Pass and merge params back to home screen
          navigation.navigate({
            name: 'Home',
            params: { orders },
            merge: true,
          });
        }}
      />
    </>
  );
}

您可以在此处查看运行示例 https://snack.expo.io/@guruparan/5b84d0

参考资料 https://reactnavigation.org/docs/params/#passing-params-to-a-previous-screen https://reactnavigation.org/docs/header-buttons/#overriding-the-back-button