我无法将参数传递给 React Native 的 props 内的函数

I can't pass arguments to a function inside props on React Native

我是 React Native 开发的新手,我很难理解为什么我传递给像 <TouchableHighlight onPress={props.executeFunction(props.label)}> 这样的函数的参数是 SyntheticBaseEvent,而不是 props.label 本身

在 App.js:37 console.log 上显示 SyntheticBaseEvent {_reactName: 'onClick', _targetInst: null, type: 'click', nativeEvent: PointerEvent, target:

我是否丢失了对原始函数的引用?

App.js:

import { StyleSheet, Text, View } from 'react-native';
import React, { Component } from 'react'
import Calculator from './Calculator';
import { LinearGradient } from 'expo-linear-gradient';

const initialState = {

  displayValue: '0',
  clearDisplay: false,
  previousOperation: null,
  operation: null,
  values: [null, null],
  currentPositionOnValues: 0,
  originalValue: 0

}

class App extends Component {
  
  constructor(props) {
    
    super(props);
    
    this.state = { ...initialState }
    this.clear = this.clear.bind(this);
    this.addDigit = this.addDigit.bind(this);

  }

  clear() {
    this.setState({ ...initialState });
  }

  addDigit(digit) {

    console.log(digit)

    if (digit === "." && this.state.displayValue.includes('.')) {

      // Prevent double decimals
      return

    }

    const clearDisplay = this.state.displayValue === '0' || this.state.clearDisplay

    /* 
        Boolean value saying if it's necessary to clear the display
        True if the currentValue display value is 0 or the variable this.state.clearDisplay is set to true
    */

    const currentValue = clearDisplay ? '' : this.state.displayValue

    /* 
        currentValue shows the 'cleared' value or the display value
    */

    const displayValue = currentValue + digit

    this.setState({ displayValue: displayValue, clearDisplay: false })

    if (digit !== '.') {

      const i = this.state.currentPositionOnValues
      const newValue = parseFloat(displayValue)
      const values = [...this.state.values]
      values[i] = newValue
      this.setState({ values: values })

    }

  }

  render() {

    return (
      <View style={styles.container}>

        <LinearGradient
          colors={['#4b6cb7', '#182848']}
          style={styles.background}
          start={[1, 1]} end={[0, 0]}
        >
        </LinearGradient>
        <Text style={styles.head}>Calculator</Text>
        <Calculator
          addDigit={() => this.addDigit}
          clear={() => this.clear}
          setOperation={() => this.setOperation}
          displayValue = {this.state.displayValue}
        />
      </View>
    );

  }
}

export default App;

Calculator.js

import React from 'react';
import { View } from 'react-native';
import Interface from './Interface';  

const Calculator = (props) => {

    return (
        <View>
            <Interface 
                addDigit={props.addDigit} 
                clear={props.clear} 
                displayValue={props.displayValue}
                setOperation={props.setOperation}
            />
        </View>
    );
    
}


export default Calculator;

Interface.js

import React from 'react';
import { View, StyleSheet, FlatList, Text } from 'react-native';
import Button from './Button';
import Display from './Display';

const Interface = (props) => {

    return (

        <View style={style.container}>

            <Display value={props.displayValue} />
            <Button label="AC" executeFunction={props.clear} triple />
            <Button label="/" executeFunction={props.setOperation} operation />
            <Button label="7" executeFunction={props.addDigit} />
            <Button label="8" executeFunction={props.addDigit} />
            <Button label="9" executeFunction={props.addDigit} />
            <Button label="*" executeFunction={props.setOperation} operation />
            <Button label="4" executeFunction={props.addDigit} />
            <Button label="5" executeFunction={props.addDigit} />
            <Button label="6" executeFunction={props.addDigit} />
            <Button label="-" executeFunction={props.setOperation} operation />
            <Button label="1" executeFunction={props.addDigit} />
            <Button label="2" executeFunction={props.addDigit} />
            <Button label="3" executeFunction={props.addDigit} />
            <Button label="+" executeFunction={props.setOperation} operation />
            <Button label="0" executeFunction={props.addDigit} double />
            <Button label="." executeFunction={props.addDigit} />
            <Button label="=" executeFunction={props.setOperation} operation />

        </View>

    );

}

const style = StyleSheet.create({

    container: {
        
        width: 400,
        borderRadius: 5,
        overflow: 'hidden',
        position: 'relative',
        justifyContent: 'center',
        flexDirection: 'row',
        flexWrap: 'wrap',
    }

})

export default Interface

Button.js

import React from "react";
import { View, StyleSheet, Text, TouchableHighlight } from "react-native";

const Button = (props) => {

    let classes = 'button '
    classes += props.operation ? 'operation' : ''
    classes += props.double ? 'double' : ''
    classes += props.triple ? 'triple' : ''

    if (props.operation) {

        return (

            <TouchableHighlight onPress={props.executeFunction(props.label)}>

                <View style={[style.button, style.operation]}>

                    <Text style={style.text}>
                        {props.label}
                    </Text>

                </View>
            </TouchableHighlight>

        )

    } else if (props.double) {

        return (

            <TouchableHighlight onPress={props.executeFunction(props.label)}>
                <View style={[style.button, style.double]}>

                    <Text style={style.text}>
                        {props.label}
                    </Text>


                </View>
            </TouchableHighlight>

        )

    } else if (props.triple) {

        return (

            <TouchableHighlight onPress={props.executeFunction()}>
                <View style={[style.button, style.triple]}>

                    <Text style={style.text}>
                        {props.label}
                    </Text>

                </View>
            </TouchableHighlight>

        )

    } else {

        return (

            <TouchableHighlight onPress={props.executeFunction(props.label)} activeOpacity={0.8}>
                <View style={[style.button]}>


                    <Text style={style.text}>
                        {props.label}
                    </Text>


                </View>
            </TouchableHighlight>

        )

    }
}

const style = StyleSheet.create({

    button: {

        width: 100,
        height: 100,
        fontSize: 30,
        backgroundColor: '#f0f0f0',
        outline: 'none',
        textAlign: 'center',
        justifyContent: 'space-evenly',

        borderColor: '#888',
        borderWidth: 1,
        borderStyle: 'solid',

    },

    double: {

        width: 200,

    },

    triple: {

        width: 300,

    },

    operation: {
        backgroundColor: '#fa8231',
        color: '#FFF',
    },

    text: {
        fontSize: 30,
        textAlign: 'center',
        justifyContent: 'space-evenly',
    }

})

export default Button

更新了您的代码:https://snack.expo.dev/qw9iqqVxs

App.JS

import { StyleSheet, Text, View } from 'react-native';
import React, { Component } from 'react';
import Calculator from './Calculator';
import { LinearGradient } from 'expo-linear-gradient';

const initialState = {
  displayValue: 0,
  clearDisplay: false,
  previousOperation: null,
  operation: null,
  values: [null, null],
  currentPositionOnValues: 0,
  originalValue: 0,
};

class App extends Component {
  constructor(props) {
    super(props);

    this.state = { ...initialState };
    this.clear = this.clear.bind(this);
    this.addDigit = this.addDigit.bind(this);
  }

  clear() {
    this.setState({ ...initialState });
  };

  addDigit(digit){
    if (digit === '.' && this.state.displayValue.includes('.')) {
      // Prevent double decimals
      return;
    }

    const clearDisplay =
      this.state.displayValue === '0' || this.state.clearDisplay;

    /* 
        Boolean value saying if it's necessary to clear the display
        True if the currentValue display value is 0 or the variable this.state.clearDisplay is set to true
    */

    const currentValue = clearDisplay ? '' : this.state.displayValue;

    /* 
        currentValue shows the 'cleared' value or the display value
    */

    const displayValue = currentValue + digit;

    this.setState({ displayValue: displayValue, clearDisplay: false })

    if (digit !== '.') {
      const i = this.state.currentPositionOnValues;
      const newValue = parseFloat(displayValue)
      const values = [...this.state.values];
      values[i] = newValue;
      this.setState({ values: values });
    }
  };

  render() {
    return (
      <View style={styles.container}>
        <LinearGradient
          colors={['#4b6cb7', '#182848']}
          style={styles.background}
          start={[1, 1]}
          end={[0, 0]}></LinearGradient>
        <Text style={styles.head}>Calculator</Text>
        <Text style={styles.head}>
          {JSON.stringify(this.state.displayValue)}
        </Text>
        <Calculator
          addDigit={(digit) => {
            this.addDigit(digit);
          }}
          clear={(value) => {
            this.clear(value)
          }}
          setOperation={this.setOperation}
          displayValue={this.state.displayValue}
        />
      </View>
    );
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
  },

  background: {
    background: 'red',
  },

  triple: {
    width: 300,
  },

  operation: {
    backgroundColor: '#fa8231',
    color: '#FFF',
  },

  text: {
    fontSize: 30,
    textAlign: 'center',
    justifyContent: 'space-evenly',
  },
});

export default App;

Button.JS

import React from "react";
import { View, StyleSheet, Text, TouchableHighlight } from "react-native";

const Button = ({operation, double, triple, executeFunction, label}) => {

    let classes = 'button '
    classes += operation ? 'operation' : ''
    classes += double ? 'double' : ''
    classes += triple ? 'triple' : ''

    if (operation) {

        return (

            <TouchableHighlight onPress={()=>executeFunction(label)}>

                <View style={[style.button, style.operation]}>

                    <Text style={style.text}>
                        {label}
                    </Text>

                </View>
            </TouchableHighlight>

        )

    } else if (double) {

        return (

            <TouchableHighlight onPress={()=>executeFunction(label)}>
                <View style={[style.button, style.double]}>

                    <Text style={style.text}>
                        {label}
                    </Text>


                </View>
            </TouchableHighlight>

        )

    } else if (triple) {

        return (

            <TouchableHighlight onPress={()=>executeFunction()}>
                <View style={[style.button, style.triple]}>

                    <Text style={style.text}>
                        {label}
                    </Text>

                </View>
            </TouchableHighlight>

        )

    } else {

        return (

            <TouchableHighlight onPress={()=>executeFunction(label)} activeOpacity={0.8}>
                <View style={[style.button]}>


                    <Text style={style.text}>
                        {label}
                    </Text>


                </View>
            </TouchableHighlight>

        )

    }
}

const style = StyleSheet.create({

    button: {

        width: 100,
        height: 100,
        fontSize: 30,
        backgroundColor: '#f0f0f0',
        outline: 'none',
        textAlign: 'center',
        justifyContent: 'space-evenly',

        borderColor: '#888',
        borderWidth: 1,
        borderStyle: 'solid',

    },

    double: {

        width: 200,

    },

    triple: {

        width: 300,

    },

    operation: {
        backgroundColor: '#fa8231',
        color: '#FFF',
    },

    text: {
        fontSize: 30,
        textAlign: 'center',
        justifyContent: 'space-evenly',
    }

})

export default Button

计算器

import React from 'react';
import { View } from 'react-native';
import Interface from './Interface';  

const Calculator = ({addDigit, clear, displayValue, setOperation}) => {

    return (
        <View>
            <Interface 
                addDigit={addDigit}
                clear={clear}
                displayValue={displayValue}
                setOperation={setOperation}
            />
        </View>
    );
    
}


export default Calculator;

Interface.JS

import React from 'react';
import { View, StyleSheet, FlatList, Text } from 'react-native';
import Button from './Button';

const Interface = ({clear, addDigit, setOperation}) => {

    return (

        <View style={style.container}>

            <Button label="AC" executeFunction={clear} triple />
            <Button label="/" executeFunction={setOperation} operation />
            <Button label="7" executeFunction={addDigit} />
            <Button label="8" executeFunction={addDigit} />
            <Button label="9" executeFunction={addDigit} />
            <Button label="*" executeFunction={setOperation} operation />
            <Button label="4" executeFunction={addDigit} />
            <Button label="5" executeFunction={addDigit} />
            <Button label="6" executeFunction={addDigit} />
            <Button label="-" executeFunction={setOperation} operation />
            <Button label="1" executeFunction={addDigit} />
            <Button label="2" executeFunction={addDigit} />
            <Button label="3" executeFunction={addDigit} />
            <Button label="+" executeFunction={setOperation} operation />
            <Button label="0" executeFunction={addDigit} double />
            <Button label="." executeFunction={addDigit} />
            <Button label="=" executeFunction={setOperation} operation />

        </View>

    );

}

const style = StyleSheet.create({

    container: {
        
        width: 400,
        borderRadius: 5,
        overflow: 'hidden',
        position: 'relative',
        justifyContent: 'center',
        flexDirection: 'row',
        flexWrap: 'wrap',
    }

})

export default Interface

发生了什么事?

当前,当组件加载时,您的代码将执行 props.executeFunction(props.label) 一次

这是因为函数在计算时立即被调用:

// directly invokes `props.executeFunction` with `props.label` because of brackets `()`
onPress={props.executeFunction(props.label)} 

因为你的函数 returns undefined,这是随后传递给 onPress 属性的内容。

有什么解决办法?

如果你想传递 props.label 那么你可以通过匿名函数传递:

onPress={() => props.executeFunction(props.label)}

onPress 属性将匿名函数附加到事件。当事件被触发时,将调用该函数,该函数将依次调用 props.executeFunction 并根据需要传递 props.label

SyntheticEvent

onPress 函数在调用处理程序时传递一个 SyntheticEvent。我们可以通过在匿名函数中记录事件来看到这一点:

onPress={(event) => console.log(event)} // SyntheticEvent

因此,如果您将 props.executeFunction 作为直接参数传递给 onPress 道具,则此事件将被传递:

onPress={props.executeFunction} // passes the event as the argument to `props.executeFunction`

例子

调用内联

这会在计算表达式(一次)时执行该函数。 undefined 被返回并传递给 onClick 所以 onClick 处理程序没有被添加。

function App(props) {
  function foo(bar) {
    console.log(bar);
  }

  return (
    <button onClick={foo("test")}>Test</button>
  );
}

ReactDOM.render(
   <App />,
   document.getElementById("react")
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>

<div id="react"></div>

通过匿名函数调用

onClick 处理程序传递匿名函数,该函数将在每次点击时执行。

如果您需要将参数传递给您的函数,这将很有用。

function App(props) {
  function foo(bar) {
    console.log(bar);
  }

  return (
    <button onClick={() => foo("test")}>Test</button>
  );
}

ReactDOM.render(
   <App />,
   document.getElementById("react")
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>

<div id="react"></div>

将函数作为参数传递

事件被传递给函数。

如果您需要访问该事件,这将很有用。

function App(props) {
  function foo(bar) {
    console.log(bar); // this logs the event as the event is passed
  }

  return (
    <button onClick={foo}>Test</button>
  );
}

ReactDOM.render(
   <App />,
   document.getElementById("react-root")
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>

<div id="react-root"></div>