Javascript react钩子有助于从基于类的组件重构

Javascript react钩子有助于从基于类的组件重构,javascript,react-hooks,Javascript,React Hooks,我有一个基于类的组件,我正试图重构它以使用钩子,但遇到了一些我无法理解的问题。我有一个surveyquestion组件,它将根据创建的问题类型显示一个下拉框、复选框等。然而,当出现新的问题时,我似乎不知道在哪里可以重新初始化基础值。非常感谢您的帮助。我只显示复选框组件函数 const CheckboxButton = ({ onClick, checked, label }) => { return ( <TouchableOpacity style={che

我有一个基于类的组件,我正试图重构它以使用钩子,但遇到了一些我无法理解的问题。我有一个surveyquestion组件,它将根据创建的问题类型显示一个下拉框、复选框等。然而,当出现新的问题时,我似乎不知道在哪里可以重新初始化基础值。非常感谢您的帮助。我只显示复选框组件函数

const CheckboxButton = ({ onClick, checked, label }) => {
  return (
    <TouchableOpacity
      style={checkboxStyles.wrapper}
      activeOpacity={1}
      onPress={() => {
        if (typeof onClick === 'function') {
          onClick(!checked);
        }
      }}
    >
      <View
        style={[
          checkboxStyles.checkbox,
          checked ? checkboxStyles.checkboxChecked : null
        ]}
      >
        {checked ? <View style={checkboxStyles.checkboxCheckedDot} /> : null}
      </View>
      <Text style={checkboxStyles.label}>{label}</Text>
    </TouchableOpacity>
  );
};

const QuestionCheckboxes = ({ question, onChange }) => {
  const [checkedIndex, setCheckedIndex] = useState([]);

  const _onChange = checked => {
    const options = question.options;
    let values = [];

    for (let i in checked) {
      if (checked[i]) {
        values.push(options[i]);
      }
    }

    if (typeof onChange === 'function') {
      onChange(values.length ? values : null);
    }
  };

  let items = [];
  for (let i = 0; i < question.options.length; ++i) {
    const option = question.options[i];
    items.push(
      <CheckboxButton
        key={i}
        label={option}
        checked={checkedIndex[i]}
        onClick={value => {
          let newCheckedIndex = [...checkedIndex];
          newCheckedIndex[i] = value;
          setCheckedIndex(newCheckedIndex);
          //need to use newCheckedIndex for onChange b/c checked index has been set
          _onChange(newCheckedIndex);
        }}
      />
    );
  }

  return <View>{items}</View>;
};

const QuestionView = ({ index, question, onChange }) => {
  const questionComponents = {
    dropdown: QuestionDropdown,
    radios: QuestionRadios,
    checkboxes: QuestionCheckboxes,
    stars: QuestionStars
  };

  if (typeof questionComponents[question.type] !== 'function') {
    return null;
  }

  const QuestionComponent = questionComponents[question.type];

  return (
    <View>
      <Text style={styles.questionTitle}>
        {index}. {question.title}
      </Text>
      <View style={styles.questionComponent}>
        <QuestionComponent question={question} onChange={onChange} />
      </View>
    </View>
  );
};

const SurveyQuestion = ({ navigation }) => {

  const [survey, setSurvey] = useState(navigation.getParam('item'));
  const questionsCount = survey.entity.data.length;
  const [current, setCurrent] = useState(0);
  const [index, setIndex] = useState(1);
  const [progress, setProgress] = useState(index / questionsCount);
  const [answers, setAnswers] = useState([]);

  _nextQuestion = async () => {
    setProgress(index / questionsCount);
    if (typeof answers[current] === 'undefined' || answers[current] === null) {
      // GeneralActions.notify('Please answer this question.');
      console.log('did not answer question');
      return;
    }

    if (current === survey.entity.data.length - 1) {
      console.log('getting ready to send to server');
      try {
        const response = await axios.post('/request', {
          id: survey.id,
          key: null,
          data: answers
        });
      } catch (err) {
        console.log('error posting survey: ', err);
      }
      return null;
    }
    setCurrent(current + 1);
    setIndex(index + 1);
  };

  return (
    <ScrollView style={styles.container}>
      <View style={styles.container}>
        <View style={styles.questions}>
          <View style={styles.progressbar}>
            <ProgressBar
              progress={progress}
              width={null}
              height={20}
              borderRadius={10}
              borderWidth={0}
              unfilledColor='#f5f5f5'
            />
          </View>
          <Text style={styles.questionsInfo}>
            {index} / {questionsCount}
          </Text>
        </View>
        <View style={styles.questionWrapper}>
          <QuestionView
            index={index}
            question={survey.entity.data[current]}
            onChange={value => {
              let newAnswers = answers.slice();
              newAnswers[current] = value;
              setAnswers(newAnswers);
            }}
          />
        </View>
        <View style={styles.action}>
          <TouchableOpacity
            style={styles.buttonPrimary}
            activeOpacity={0.7}
            onPress={_nextQuestion}
          >
            <Text style={styles.button}>
              {progress === 1 ? 'FINISH' : 'NEXT'}
            </Text>
          </TouchableOpacity>
        </View>
      </View>
    </ScrollView>
  );
};
const CheckboxButton=({onClick,checked,label})=>{
返回(
{
if(onClick的类型=='function'){
onClick(!checked);
}
}}
>
{已检查?:空}
{label}
);
};
常量问题复选框=({question,onChange})=>{
常量[checkedIndex,setCheckedIndex]=useState([]);
const\u onChange=checked=>{
const options=question.options;
让值=[];
对于(让我检查){
如果(选中[i]){
推送(选项[i]);
}
}
if(类型onChange=='function'){
onChange(values.length?值:null);
}
};
设项目=[];
for(设i=0;i
);
}
返回{items};
};
const QuestionView=({index,question,onChange})=>{
常量组件={
下拉列表:问题下拉列表,
收音机:收音机,
复选框:问题复选框,
星星:星星
};
if(问题组件的类型[问题类型]!==“函数”){
返回null;
}
const QuestionComponent=questionComponents[question.type];
返回(
{index}.{question.title}
);
};
const SurveyQuestion=({navigation})=>{
const[survey,setSurvey]=useState(navigation.getParam('item');
const questionScont=survey.entity.data.length;
const[current,setCurrent]=useState(0);
const[index,setIndex]=useState(1);
const[progress,setProgress]=使用状态(索引/问题查询);
const[answers,setAnswers]=useState([]);
_nextQuestion=async()=>{
设置进度(索引/问题查询);
如果(答案类型[当前]=='未定义'| |答案[当前]==空){
//通知('请回答此问题');
log('没有回答问题');
返回;
}
if(当前===survey.entity.data.length-1){
log(“准备发送到服务器”);
试一试{
const response=wait axios.post(“/request”{
id:survey.id,
key:null,
数据:答案
});
}捕捉(错误){
console.log('error posting survey:',err);
}
返回null;
}
设置电流(电流+1);
setIndex(index+1);
};
返回(
{index}/{questionsCount}
{
让newAnswers=answers.slice();
新答案[当前]=值;
设置答案(新答案);
}}
/>
{progress==1?'FINISH':'NEXT'}
);
};
目前,当我从一个问题转到另一个问题时,旧的答案将继续存在。例如,我不知道在哪里可以将checkedIndex重新初始化回[]

常量[checkedIndex,setCheckedIndex]=useState([])


我尝试将setCheckedIndex([])放在几个区域,但重新渲染的次数太多。

这可能是因为它在每次渲染之间重复使用相同的
QuestionComponent
组件。我无法对其进行测试,但我会尝试添加一个唯一的键,以提供一个“提示”,以便在键发生更改时做出反应,即它应该创建一个新组件

<QuestionComponent
  key={question.uniqueIdOrSomething}
  question={question}
  onChange={onChange}
/>;
其中,
uniqueIdOrSomething
可以是问题
id
或问题
text
(可以唯一识别问题的任何内容)

通常,在列表中使用
,以便在顺序发生变化时可以重用组件(性能优化)。但是,它也可以用来告诉React这个组件是不同的,它不应该重用现有组件并重新实例化它。对于您来说,这将擦除现有状态并提供新的默认值。我认为这是使用
的正确用例,但是过度使用这种方法(添加
道具)时要小心,因为它可能会掩盖其他问题


有关
属性的更多详细信息:

这可能是因为它在每次渲染之间重用了相同的
QuestionComponent
组件。我无法对其进行测试,但我会尝试添加一个唯一的键,以提供一个“提示”,以便在键发生更改时做出反应,即它应该创建一个新组件

<QuestionComponent
  key={question.uniqueIdOrSomething}
  question={question}
  onChange={onChange}
/>;
其中,
uniqueIdOrSomething
可以是问题
id
或问题
text
(可以唯一识别问题的任何内容)

通常,在列表中使用
,以便在顺序发生变化时可以重用组件(性能优化)。但是,它也可以用来告诉React这个组件是不同的,它不应该重用现有组件并重新实例化它。对于您来说,这将擦除现有状态并提供新的默认值。我认为这是使用
的正确用例,但是过度使用这种方法(添加
道具)时要小心,因为它可能会掩盖其他问题

更多详情