反应本机渲染按钮列表无法弄清楚出了什么问题

react native rendering a list of buttons can't figure out what's wrong

我正在尝试根据用户的输入创建一个按钮列表,输入类型是一个选项数组,就像这样multipleOptions = ['1', '2', '3']然后我们遍历每个选项以显示一个按钮无法弄清楚为什么它不起作用这是我的代码:

import React, { useState } from 'react';
import { StyleSheet, Text, TouchableOpacity, View } from 'react-native';

const InputButton = (multipleOptions, likertScale, onPress) => {
  const [options, setOptions] = useState([]);
  if (likertScale) {
    setOptions([...new Array(likertScale).keys()].map((i) => i));
  } else if (multipleOptions) setOptions(multipleOptions);

  return (
    <View style={styles.container}>
      {options ? (
        options.map((option, i) => (
          <View style={[styles.button]} key={`${i}`}>
            <TouchableOpacity onPress={() => onPress(option)}>
              <Text>{option}</Text>
            </TouchableOpacity>
          </View>
        ))
      ) : (
        <Text>no options</Text>
      )}
    </View>
  );
};

const App = () => {
  return (
    <View>
      <InputButton multipleOptions={['1', '2','3']} />
    </View>
  )
}
const styles = StyleSheet.create({})

export default App;

const styles = StyleSheet.create({
  container: {
    flexDirection: 'row',
  },
  button: {
    margin: 3,
    flex: 1,
    backgroundColor: '#EEF6FA',
    minHeight: 72,
    borderRadius: 2,
    justifyContent: 'center',
    alignItems: 'center',
  },
});
 

错误信息是

Too many re-renders. React limits the number of renders to prevent an infinite loop.

或者有时这个

options.map is not a function
TypeError: options.map is not a function
    at InputButton 

(欢迎各种优化) 在此先感谢大家。

代码演示https://snack.expo.io/@mansouriala/dac832

这里有几个问题。

第一个,导致 Too many re-renders. React limits the number of renders to prevent an infinite loop. 是因为你在每次渲染时调用 setOptions,这会触发另一个渲染,等等......这是无限循环,因为当你设置状态,React 重新渲染组件。为避免这种情况,您必须用 useEffect 和正确的依赖关系包裹您的表达式。

React.useEffect(() => {
  if (likertScale) {
    setOptions([...new Array(likertScale).keys()].map((i) => i));
  } else if (multipleOptions) {
    setOptions(multipleOptions);
  }, [multipleOptions, likertScale]);

这样,当 multipleOptionslikertScale 改变时,这个表达式只会 运行。 https://reactjs.org/docs/hooks-reference.html#useeffect

另一个问题是 InputButton props 参数是错误的:你忘记了 props 的解构。应该是 const InputButton = ({ multipleOptions, likertScale, onPress }) => { /* body function */ }.

最后,将数组索引用作 key 道具是一种不好的做法,因为数组顺序可能会改变。您应该使用稳定密钥,例如选项值 key={option}.

https://reactjs.org/docs/lists-and-keys.html#keys

你在每次重新渲染时都设置了状态,所以你得到了一个循环。所以你有两个选择使用 useEffect 只设置一次状态或直接设置第一个状态。 https://snack.expo.io/ZvLQM9FEF

const InputButton = ({multipleOptions, likertScale, onPress}) => {
  const [options, setOptions] = useState(likertScale?[...new Array(likertScale).keys()].map((i) => i):[ ...multipleOptions]);

  return (
    <View style={styles.container}>
      {options ? (
        options.map((option, i) => (
          <View style={[styles.button]} key={`${i}`}>
            <TouchableOpacity onPress={() => onPress(option)}>
              <Text>{option}</Text>
            </TouchableOpacity>
          </View>
        ))
      ) : (
        <Text>no options</Text>
      )}
    </View>
  );
};

export default InputButton;