React Native——onPress 从“currentTarget”中提取 id

ale*_*s84 1 react-native onpress

我在 React 上创建了一个游戏,我正在尝试将我的代码调整为 React Native。困扰我的一件事是如何翻译这三行,因为在 RN 中没有可依赖的 DOM 解决方案:

handleClick(e) {

this.props.change(e.currentTarget.id);

}  
Run Code Online (Sandbox Code Playgroud)

这里发生的事情是一个无状态的孩子正在收集一个被点击的元素 id(currentTarget 的),并使用它来调用在父元素中定义的方法。e.currentTarget.id然而,这种公式在 RN 中不起作用。

有没有一种雄辩的方法可以在 RN 中重写这一行?

注意:这里这里有两个与此类似的问题,但答案看起来更像是补丁而不是结构优雅的解决方案。如果您知道某些事情,请发布答案。

编辑:似乎不能绕过 ReactNativeComponentTree。

到目前为止,我有这么多,但这还不起作用:

handlePress(event) {

let number =  ReactNativeComponentTree.getInstanceFromNode(event.currentTarget)._currentElement.id;

this.props.change(number);

}  
Run Code Online (Sandbox Code Playgroud)

第二次编辑:好吧,也许我应该添加一个我想要实现的简单示例。当我点击任何平面列表的元素时,它的 id 应该显示在 Child 的底部。单击重置将恢复默认状态。

下面的简单示例代码:

    import React, { Component } from 'react';
    import { AppRegistry, FlatList, StyleSheet, Text, View, Button } from 'react-native';
    import ReactNativeComponentTree from 'react-native';

    export default class Parent extends Component {

      constructor(props) {
        super(props);    

        this.state = {  

                quotes: ["a","bnaskdkahhahskkdk","c","d","e","a","b","c","d"],
                    size: [true, true, true, true, true, true, true, true, true],
                    color: [false, false, false, false, false, false, false, false, false],
                    progress: "me"

        };

        this.change = this.change.bind(this);
        this.reset = this.reset.bind(this);

      }

      change(number) {

      this.setState({color: [true, true, true, true, true, true, true, true, true],              progress: number});

      }

      reset() {

        this.setState({color: [false, false, false, false, false, false, false, false, false],
                       progress: "me"
        });

      }

      render() {
        return (
          <View style={styles.container}>
    <Child change={this.change} reset={this.reset} quotes={this.state.quotes} 
           size={this.state.size} color={this.state.color} 
           progress={this.state.progress} />
          </View>
        );
      }
    }

    class Child extends Component {

        constructor(props) {

        super(props);    

        this.handlePress = this.handlePress.bind(this);
        this.handleReset = this.handleReset.bind(this);
      }

        /*handlePress(e) {
          let number = e.currentTarget.id;
            this.props.change(number);
        }*/

        handlePress(event) {

    let number =  ReactNativeComponentTree.getInstanceFromNode(event.currentTarget)._currentElement.id;

    this.props.change(number);

    }  

        handleReset() {
          this.props.reset();
        }

      render() {

        let ar = [];

        for (let i=0; i<this.props.quotes.length; i++) {
          let b = {key: `${i}`, id: i, 
              classSize: this.props.size[i] ? (i%2===0 ? styles.size : styles.oddsize) : "", 
              classColor: this.props.color[i] ? (i%2===0 ? styles.color : styles.oddcolor) : ""}
          ar.push(b);      

        }

        return (
        <View style={styles.container}>
          <Button onPress={this.handleReset} title="Reset" />
            <FlatList
              data={
                ar
              }

    renderItem={({item}) => <Text onPress={this.handlePress} 
    style={[item.classSize, item.classColor]}> {item.id+1} 
    {this.props.quotes[item.id]} </Text> }

            /> 

        <Text style={styles.size}>{this.props.progress}</Text>

        </View>
        );
      }
    }


    const styles = StyleSheet.create({
      container: {
       flex: 1,
       flexDirection: "column",
       //justifyContent: "center",
       alignItems: "center",
       paddingTop: 22,
       //backgroundColor: "purple" 
      },
      size: {
        flex: 1,
        padding: 10,
        fontSize: 18,
        backgroundColor: "grey",
        margin: 1,
        height: 44,
        color: 'gold',
        borderColor: "white",
        borderWidth: "1",
        textAlign: "center"
      },
      oddsize: {
        flex: 1,
        padding: 10,
        fontSize: 18,
        backgroundColor: "white",
        margin: 1,
        height: 44,
        color: 'gold',
        borderColor: "white",
        borderWidth: "1",
        textAlign: "center"
      },
      color: {
        flex: 1,
        padding: 10,
        backgroundColor: 'grey',
        //borderRadius: "25%",
        margin: 1,
        fontSize: 18,
        height: 44,
        color: 'pink',
        borderColor: "red",
        borderWidth: "1"
      },
    oddcolor: {
        flex: 1,
        padding: 10,
        backgroundColor: 'white',
        //borderRadius: "25%",
        margin: 1,
        fontSize: 18,
        height: 44,
        color: 'pink',
        borderColor: "red",
        borderWidth: "1"
      }
    })

    // skip this line if using Create React Native App
    AppRegistry.registerComponent('AwesomeProject', () => Parent);
Run Code Online (Sandbox Code Playgroud)

Flo*_*ues 5


获取当前按下的元素属性(在本例中
为id )的更好方法(避免在每次渲染时创建事件回调)是将其包装在父组件中,仅传递数据
并绑定所有事件一次(在构造函数中)

  1. 首先声明你的组件包装器:
    它需要是一个类而不是一个无状态的功能组件,否则你无法避免在每次渲染时创建回调

要查看差异,这里有一个更高级的示例:
https : //snack.expo.io/ByTEKgEsZ示例源代码

class TouchableText extends React.PureComponent {
  constructor(props) {
    super(props);
    this.textPressed = this.textPressed.bind(this);
  }
  
  textPressed(){
    this.props.onPressItem(this.props.id);
  }

  render() {
    return (
      <Text style={styles.item} onPress={this.textPressed}>
        {this.props.children}
      </Text>
    );
  }
}
Run Code Online (Sandbox Code Playgroud)

如果您使用 const JSX 对象(无状态功能组件),它可以工作但不是最佳的,每次渲染组件时都会创建事件回调,因为箭头函数实际上是渲染函数的快捷方式

const TouchableText = props => {
  const textPressed = () => {
    props.onPressItem(props.id);
  };
  return <Text onPress={textPressed} />;
};
Run Code Online (Sandbox Code Playgroud)
  1. 然后使用此包装器代替您的组件,如下所示:
class Test extends React.Component {
  constructor(props) {
    super(props);
    //event binding in constructor for performance (happens only once)
    //see facebook advice: 
    //https://facebook.github.io/react/docs/handling-events.html
    this.handlePress = this.handlePress.bind(this);
  }

  handlePress(id) {
    //Do what you want with the id
  }

  render() {
    return (
      <View>
        <FlatList
          data={ar}
          renderItem={({ item }) => (
            <TouchableText
              id={item.id}
              onPressItem={this.handlePress}
            >
              {`Component with id ${item.id}`}
            </TouchableText>
          )}
        />
      </View>
    );
  }
}
Run Code Online (Sandbox Code Playgroud)

正如React Native Handling Events Doc 中所写,还有另一种可能的语法可以避免在构造函数中绑定(虽然是实验性的:即将来可能支持也可能不支持!):

如果调用 bind 使您烦恼,有两种方法可以解决这个问题。如果您使用的是实验属性初始化器语法,则可以使用属性初始化器正确绑定回调

这意味着我们只能写

handlePress = (id) => {
    //`this` is already bound!
}
Run Code Online (Sandbox Code Playgroud)

代替

constructor(props) {
    super(props);
    //manually bind `this` in the constructor
    this.handlePress = this.handlePress.bind(this);
}
Run Code Online (Sandbox Code Playgroud)
handlePress(id) {

}
Run Code Online (Sandbox Code Playgroud)

一些参考资料:
事件处理程序和功能无状态组件
React 绑定模式:5 种处理此问题的方法