Javascript react钩子有助于从基于类的组件重构
我有一个基于类的组件,我正试图重构它以使用钩子,但遇到了一些我无法理解的问题。我有一个surveyquestion组件,它将根据创建的问题类型显示一个下拉框、复选框等。然而,当出现新的问题时,我似乎不知道在哪里可以重新初始化基础值。非常感谢您的帮助。我只显示复选框组件函数Javascript react钩子有助于从基于类的组件重构,javascript,react-hooks,Javascript,React Hooks,我有一个基于类的组件,我正试图重构它以使用钩子,但遇到了一些我无法理解的问题。我有一个surveyquestion组件,它将根据创建的问题类型显示一个下拉框、复选框等。然而,当出现新的问题时,我似乎不知道在哪里可以重新初始化基础值。非常感谢您的帮助。我只显示复选框组件函数 const CheckboxButton = ({ onClick, checked, label }) => { return ( <TouchableOpacity style={che
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这个组件是不同的,它不应该重用现有组件并重新实例化它。对于您来说,这将擦除现有状态并提供新的默认值。我认为这是使用键
的正确用例,但是过度使用这种方法(添加键
道具)时要小心,因为它可能会掩盖其他问题
更多详情