简体   繁体   English

反应原生渲染按钮列表无法找出问题所在

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

I'm trying to make a list of buttons based on the input from user input type is an array of options like so multipleOptions = ['1', '2', '3'] then we loop through each option to show a Button can't figure out why it's not working here's my code:我正在尝试根据用户输入类型的输入创建一个按钮列表,它是一个选项数组,例如multipleOptions = ['1', '2', '3']然后我们遍历每个选项以显示一个 Button无法弄清楚为什么它不起作用这是我的代码:

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',
  },
});
 

the error message is错误信息是

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

or sometimes this或者有时这个

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

(All kind of optimisations are welcome) Thanks in Advance guys. (欢迎各种优化)提前谢谢大家。

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

You have several issues here.你在这里有几个问题。

The first, which leads to Too many re-renders. React limits the number of renders to prevent an infinite loop.第一个,这导致了Too many re-renders. React limits the number of renders to prevent an infinite loop. Too many re-renders. React limits the number of renders to prevent an infinite loop. is because you're calling setOptions at each render, which triggers another render, etc… This is infinite loop, because when you're setting a state, React re-renders the component.是因为您在每次渲染时调用setOptions ,这会触发另一个渲染,等等……这是无限循环,因为当您设置 state 时,React 会重新渲染组件。 To avoid that, you have to wrap your expression with useEffect and the correct dependencies.为避免这种情况,您必须使用useEffect和正确的依赖项来包装您的表达式。

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

This way, this expression would only run when multipleOptions or likertScale change.这样,这个表达式只会在multipleOptionslikertScale改变时运行。 https://reactjs.org/docs/hooks-reference.html#useeffect https://reactjs.org/docs/hooks-reference.html#useeffect

The other problem is that InputButton props argument is wrong: you forgot the props destructuring.另一个问题是InputButton道具参数是错误的:你忘记了道具解构。 It should be const InputButton = ({ multipleOptions, likertScale, onPress }) => { /* body function */ } .它应该是const InputButton = ({ multipleOptions, likertScale, onPress }) => { /* body function */ }

Finally, it's a bad practice to use an array index as a key prop, because array order could change.最后,使用数组索引作为key prop 是一种不好的做法,因为数组顺序可能会改变。 You should use a stable key, like the option value key={option} .您应该使用稳定的密钥,例如选项值key={option}

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

You put set state in every re-render so you get a loop.你在每次重新渲染中都设置了 state ,这样你就得到了一个循环。 So you have two options use useEffect to just set state one time or set the first state directly.因此,您有两个选项使用 useEffect 来设置一次 state 或直接设置第一个 state。 https://snack.expo.io/ZvLQM9FEF 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;

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM