首页 > 解决方案 > 对 props 块组件中的本机回调函数做出反应以重新渲染

问题描述

我有这个反应原生组件,它创建一个带有增加和减少按钮的通用数字输入。

带按钮的数字输入

export default function NumberInput({quantity = 0, onquantityChange}) {
  const [number, SetNumber] = useState(quantity);

  function handleIncrease() {
    SetNumber(number + 1);
    onquantityChange(quantity + 1);
  }


  function handleDecrease() {
    if (number > 0) {
      SetNumber(number - 1);
      onquantityChange(quantity - 1);
    }
  }

  return (
    <View style={styles.container}>
      <TouchableOpacity onPress={handleDecrease} activeOpacity={0.6}>
        <Icon name="minus" size={20} color={colors.white} style={styles.icon} />
      </TouchableOpacity>
      <AppText style={styles.text}>{number}</AppText>
      <TouchableOpacity onPress={handleIncrease} activeOpacity={0.6}>
        <Icon name="plus" size={20} color={colors.white} style={styles.icon} />
      </TouchableOpacity>
    </View>
  );
}

当我按下 + 或 - 按钮时,onquantityChange功能会使数字的增加和减少变慢,如果我评论它,它将几乎实时重新渲染。(onquantityChange函数在父函数中做了一些繁重的工作)。

我也用过这个版本,稍微好一点但没有太大变化:

  const [number, SetNumber] = useState(quantity);

  function handleIncrease() {
    SetNumber(number + 1);
  }

  useEffect(() => {
    onquantityChange(number);
  }, [number]);

  function handleDecrease() {
    if (number > 0) {
      SetNumber(number - 1);
    }
  }

我该怎么做才能使数字和 UI 重新呈现并且不等待onquantityChange

标签: javascriptreactjsreact-native

解决方案


通过setTimeout在 useEffect 中使用,我们可以使onquantityChange每次number更改时都不运行,setTimeout 也可以在“堆栈为空时”运行它。

在主线程上的堆栈为空之前,您传递给这些函数的回调无法运行。

引用MDN

所以我把我的功能组件改成了这个。

//this have to be outside of the function component.
let changeTimeout;

export default function NumberInput({value = 0, onChange}) {
  const [number, SetNumber] = useState(value);

  function handleIncrease() {
    SetNumber(number + 1);
  }

  //use setTimeout to delay onChange to a time when main thread is available 
  useEffect(() => {
    changeTimeout && clearTimeout(changeTimeout);
    changeTimeout = setTimeout(() => {
      onChange(number);
    }, 500);
  }, [number]);

  function handleDecrease() {
    if (number > 0) {
      SetNumber(number - 1);
    }
  }

  return (
    <View style={styles.container}>
      <TouchableOpacity onPress={handleDecrease} activeOpacity={0.7}>
        <Icon name="minus" size={20} color={colors.white} style={styles.icon} />
      </TouchableOpacity>
      <AppText style={styles.text}>{number}</AppText>
      <TouchableOpacity onPress={handleIncrease} activeOpacity={0.7}>
        <Icon name="plus" size={20} color={colors.white} style={styles.icon} />
      </TouchableOpacity>
    </View>
  );
}

欢迎任何其他建议。


推荐阅读