首页 > 解决方案 > 如何在 React Native 中重置子组件中的计数器

问题描述

我有一个 PlusMinus 组件,其目的是让用户增加或减少一个整数。在我的父组件中,我遍历列表中的几个项目并为每个项目提供一个 PlusMinus 计数器。

如何重置父组件中的所有计数器?此类问题的大多数答案都建议在父级中处理状态,使子级无状态,并通过道具将值传递给子级。但是,当我在父项中更新这些道具值时,子项不会更新。一些答案组件WillReceiveProps。但是,该功能已被弃用,无论如何我都无法让它工作。

这是我的组件。它有效,但我无法重置计数器。如何在我的父母中提供一个重置所有子计数器的按钮?

import * as React from 'react'
import { Text, TouchableOpacity, View } from 'react-native'

import styles from './Styles'

type Props = { k: string, handler: Function, style: Object }
type State = { clicks: Object }

export default class PlusMinus extends React.Component<Props, State> {

  state = {
    clicks: {}
  }

  IncrementItem = (k: string) => {

    let clicks = this.state.clicks

    if ('undefined' == typeof this.state.clicks[k]) {
      clicks[k] = 1
    }
    else {
      clicks[k]++
    }

    // A handler passed from the parent that updates persistent values in the parent.
    this.props.handler(k, clicks[k])

    this.setState(
      { clicks: clicks }
    )
  }

  DecreaseItem = (k: string) => {

    let clicks = this.state.clicks

    if ('undefined' == typeof this.state.clicks[k]) {
      clicks[k] = 0
    }
    else if (this.state.clicks[k] > 0) {
      clicks[k]--
    }

    this.props.handler(k, clicks[k])

    this.setState(
      { clicks: clicks }
    )
  }

  Count = (k: string) => {
    let ct = 0

    if ('undefined' !== typeof this.state.clicks[k]) {
      ct = this.state.clicks[k]
      ct = ct++
    }
    return (
      <Text style={styles.counter} id={k}>{ ct }</Text>
    )
  }

  render() { 
    return (
      <View style={this.props.style}>
        <TouchableOpacity style={styles.plusminus} title='+' onPress={() => this.IncrementItem(this.props.k)}>
          <Text style={styles.pmtxt}>+</Text>
        </TouchableOpacity>
        <TouchableOpacity style={styles.plusminus} title='-' onPress={() => this.DecreaseItem(this.props.k)}>
          <Text style={styles.pmtxt}>-</Text>
        </TouchableOpacity>

        <View style={[{ 
          paddingHorizontal: 10,
          marginLeft: 4,
          alignItems: 'center',
          justifyContent: 'center',
          backgroundColor: '#aaa',
          width: 40,
          borderRadius: 5
        }]}>{this.Count(this.props.k)}</View>
      </View>
    )
  }
}

我在父组件中的处理程序看起来像......

handler = async (key: string, value: Number) => {
    let object = {}
    let str = await Expo.SecureStore.getItemAsync('clicks')
    if (str) {
      object = JSON.parse(str)
    }
    object[key] = value
    str = JSON.stringify(object)
    Expo.SecureStore.setItemAsync('clicks', str)
  }

-------- 更新:这是一个工作示例。--------

import * as React from 'react'
import { Text, TouchableOpacity, View } from 'react-native'

import styles from './Styles'

type Props = { k: string, handler: Function, style: Object, clicks: Number }

export default class PlusMinus extends React.Component<Props> {

  IncrementItem = (k: string) => {
    let clicks = this.props.clicks
    this.props.handler(k, clicks, '++')
  }

  DecreaseItem = (k: string) => {
    let clicks = this.props.clicks
    this.props.handler(k, clicks, '--')
  }

  Count = (k: string) => {
    let ct = 0

    if ('undefined' !== typeof this.props.clicks) {
      ct = this.props.clicks
    }
    return (
      <Text style={styles.counter} id={k}>{ ct }</Text>
    )
  }

  render() { 
    return (
      <View style={this.props.style}>
        <TouchableOpacity style={styles.plusminus} title='+' onPress={() => this.IncrementItem(this.props.k)}>
          <Text style={styles.pmtxt}>+</Text>
        </TouchableOpacity>
        <TouchableOpacity style={styles.plusminus} title='-' onPress={() => this.DecreaseItem(this.props.k)}>
          <Text style={styles.pmtxt}>-</Text>
        </TouchableOpacity>

        <View style={[{ 
          paddingHorizontal: 10,
          marginLeft: 4,
          alignItems: 'center',
          justifyContent: 'center',
          backgroundColor: '#aaa',
          width: 40,
          borderRadius: 5
        }]}>{this.Count(this.props.k)}</View>
      </View>
    )
  }
}

以及父组件的工作处理程序......

 handler = async (key: string, value: Number, pm: string) => {

    let ct = 1
    let n = this.state.clicks[key]

    if ('++' == pm) {
      ct = n
      ct++
    }
    else {
      ct = 0
      if (n > 0) {
        ct = n
        ct--
      }
    }

    let clicks = this.state.clicks
    clicks[key] = ct

    this.setState({clicks: clicks})
  }

以及父渲染中子组件的 JSX...

<PlusMinus k={k} clicks={this.state.clicks[k]} style={{
                        flexWrap: 'wrap',
                        flexDirection: 'row',
                        marginBottom: 0,
                        marginRight: 12,
                        paddingBottom: 0,
                        paddingRight: 5,
                        paddingLeft: 5
                      }} handler={this.handler} />

标签: react-nativeparent-childstate

解决方案


我相信最好的方法正是您所描述的:您的父组件应该处理点击并将其作为道具传递给子组件,其中点击数来自状态,例如:

state = { clicks: [] }
...
<PlusMinus clicks={this.state.clicks[i]} />

然后,当您想要重置点击时,您只需在 this.state.clicks 上运行一个循环并将所有项目设置为 0(显然,通过使用新数组调用 setState)。当然,子组件可以是无状态的,并且递增/递减函数应该移动到父组件。


推荐阅读