如何在React Native中重置子组件中的计数器

时间:2018-05-15 18:42:26

标签: react-native parent-child state

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

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

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

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} />

1 个答案:

答案 0 :(得分:1)

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

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

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