【问题标题】:Accessing child state from parent从父级访问子状态
【发布时间】:2020-12-09 14:04:37
【问题描述】:

背景

我正在构建一个应用程序,该应用程序在某些时候具有一个呈现产品的 FlatList。列表的代码如下所示:

<FlatList
                data={data}
                renderItem={({ item }) => (
                    <View style={styles.container}>
                        <View style={styles.left}>
                            <Text style={styles.title}>{item.name}</Text>
                            <Text style={styles.description}>{item.description}</Text>
                            <Text style={styles.price}>${item.price}</Text>
                            <Counter />
                        </View>
                        <Image style={styles.right} source={{uri: item.image}}/>
                    </View>
                )}
            /> 

此列表的数据来自 Google Cloud Firestore 文档。在这个列表中,您可以看到一个名为Counter 的组件,它的工作是允许用户从他们的购物车中添加和删除产品。这是它的代码:

export default function Counter () {  


    const [count, setCount] = useState(0);

      const handleAddition=()=>{
        setCount(count + 1)
      }

      const handleDeletion=()=>{
        {count === 0 ? setCount(count) : setCount(count - 1)}
      }
return ( 
    
    <View style={styles.adder}>
        <TouchableOpacity onPress={() => {handleDeletion()}}>
            <Text style={styles.less}>-</Text>
        </TouchableOpacity>
        <Text style={styles.counter}>{count}</Text>
        <TouchableOpacity onPress={() => {handleAddition()}}>
            <Text style={styles.more}>+</Text>
        </TouchableOpacity>
    </View>

)
}

问题

从我在 FlatList 中呈现计数器这一事实可以看出,我需要将状态存储在子级而不是父级中,因为在父级中拥有计数意味着如果用户选择一个产品,同时添加每个项目。

当用户选择允许他们导航到购买摘要的产品时,我需要显示一个按钮,并且我需要该按钮来显示他们选择的总成本和选择的产品数量。正如你可能想象的那样,我不知道如何在父组件中访问子组件的状态。

所以总结一下: 我有一个孩子的状态更新,我需要从它的父母那里访问,但我不知道该怎么做。

问题¨

有什么方法可以监听孩子状态的事件变化或将其作为道具传递或类似的东西?

提前非常感谢!

额外信息

这是显示屏幕 UI 的图像。当按下“+”按钮时,它会更新计数 +1,它还应该显示一个显示我之前提到的信息的按钮。

【问题讨论】:

  • 类似这样的东西:i.stack.imgur.com/N1YWc.gif?
  • 是的,已经足够接近了。 FlatList 显示可以添加或删除产品的项目。此外,它会显示一个允许用户进入购物车的按钮。
  • 这是上面例子的答案:stackoverflow.com/a/65152082/5669120
  • 非常感谢,但查看代码,这不是我想要的。
  • 如果可能,添加 UI 和数据流,会调查它。这会让问题更清楚。

标签: javascript reactjs react-native


【解决方案1】:

在 renderItem 中你可以在这里传递方法回调

&lt;Counter onPressFunctionItem={(isPlus) =&gt; { // handle from parent here }} /&gt;

export default function Counter ({ onPressFunctionItem }) {  


    const [count, setCount] = useState(0);

      const handleAddition=()=>{
        setCount(count + 1)
        if (onPressFunctionItem) {
          onPressFunctionItem(true)
        }
      }

      const handleDeletion=()=>{
        {count === 0 ? setCount(count) : setCount(count - 1)}
        if (onPressFunctionItem) {
          onPressFunctionItem(false)
        }
      }
   return (...)
}

【讨论】:

    【解决方案2】:

    最终输出:

    您实际上不需要将子组件的状态传递给父组件来获得相同的结果,您可以通过常规方式非常轻松地做到这一点。

    这是上面例子的源代码:

    export default function App() {
      const [products, setProducts] = useState(data);
    
      /* 
      with this function we increase the quantity of 
      product of selected id
      */
      const addItem = (item) => {
        console.log("addItem");
        let temp = products.map((product) => {
          if (item.id === product.id) {
            return {
              ...product,
              quantity: product.quantity + 1,
            };
          }
          return product;
        });
    
        setProducts(temp);
      };
    
      /* 
      with this function we decrease the quantity of 
      product of selected id, also put in the condition so as 
      to prevent that quantity does not goes below zero
      */
      const removeItem = (item) => {
        console.log("removeItem");
        let temp = products.map((product) => {
          if (item.id === product.id) {
            return {
              ...product,
              quantity: product.quantity > 0 ? product.quantity - 1 : 0,
            };
          }
          return product;
        });
        setProducts(temp);
      };
    
      /*
       this varible holds the list of selected products.
      if required, you can use it as a seperate state and use it the 
      way you want
       */
      let selected = products.filter((product) => product.quantity > 0);
    
      /**
       * below are two small utility functions,
       * they calculate the total itmes and total price of all
       * selected items
       */
      const totalItems = () => {
        return selected.reduce((acc, curr) => acc + curr.quantity, 0);
      };
      const totalPrice = () => {
        let total = 0;
        for (let elem of selected) {
          total += elem.quantity * elem.price;
        }
        return total;
      };
    
      useEffect(() => {
        console.log(products);
      }, [products]);
    
      return (
        <View style={styles.container}>
          <FlatList
            data={products}
            renderItem={({ item }) => {
              return (
                <Card style={styles.card}>
                  <View style={styles.textBox}>
                    <Text>{item.name}</Text>
                    <Text>$ {item.price.toString()}</Text>
                    <View style={{ flexDirection: "row" }}></View>
                    <View style={styles.buttonBox}>
                      <Button
                        onPress={() => removeItem(item)}
                        title="-"
                        color="#841584"
                      />
                      <Text>{item.quantity.toString()}</Text>
                      <Button
                        onPress={() => addItem(item)}
                        title="+"
                        color="#841584"
                      />
                    </View>
                  </View>
                  <Image
                    style={styles.image}
                    source={{
                      uri: item.image,
                    }}
                  />
                </Card>
              );
            }}
          />
    
          <View style={{ height: 60 }}></View>
    
          {selected.length && (
            <TouchableOpacity style={styles.showCart}>
              <View>
                <Text style={styles.paragraph}>
                  {totalItems().toString()} total price ${totalPrice().toString()}
                </Text>
              </View>
            </TouchableOpacity>
          )}
        </View>
      );
    }
    

    您可以在此处找到工作应用演示:Expo Snack

    【讨论】:

    • 您的回答非常棒,非常有帮助,非常感谢!
    • 很高兴它帮助了 Luis。快乐编码:)
    • 我有一个问题,不过,我不明白item.quantity.toString() 的来源。一旦我更换了一些东西,这就是引发错误的一件事,因此它可以与 firestore 一起使用。
    • 我添加了一个数量键来跟踪添加到购物车的商品总数,如果您的 Firebase 数据没有,请添加它,您的工作会轻松很多。
    • 不客气,这真是一个有趣的问题,真的很喜欢把它放在一起。再见,布埃纳斯,noches。
    猜你喜欢
    • 2021-11-05
    • 1970-01-01
    • 1970-01-01
    • 2017-06-09
    • 1970-01-01
    • 2020-10-05
    • 2020-06-26
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多