我正在模拟器中运行一个应用,并尝试调试某些无法正确呈现的组件Questionnaire
。该组件的render()
方法包含以下内容:
render() {
if (this.props.questionCount === 0) {
return (
<View style={styles.loading}>
<ActivityIndicator size="large" />
</View>
);
}
因此,如果questionCount
道具为零,它将仅“挂”在活动指示器上。这确实是我在模拟器中看到的。
要找出原因,我想找出Questionnaire
的渲染位置,以便可以看到道具如何传递给它。但是,我在代码范围内搜索了<Questionnaire>
,但是没有得到任何结果。
我知道该应用程序使用Redux,并且在React Native Debugger窗口中,好像正在调用Connect(Questionnaire)
(见下文)。
找到呈现Questionnaire
的代码部分以及传递给它的道具的正确方法是什么?
为完整起见,以下是Questionnaire
组件的代码:
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import {
ActivityIndicator,
Dimensions,
Platform,
ScrollView,
StatusBar,
TouchableOpacity,
View,
} from 'react-native';
import Modal from 'react-native-modal';
import { Actions } from 'react-native-router-flux';
import AndroidKeyboardAdjust from 'react-native-android-keyboard-adjust';
import { LOADING_SESSION_SMATTER, ADDRESS_FORM } from 'app/src/scenes';
import { loggingOut } from 'app/src/containers/login/login.actions';
import Text from 'app/src/components/text';
import { resetScene } from 'app/src/lib/utils';
import QuestionnaireHeader from './components/questionnaireHeader';
import QuestionWrapper from './questions/questionWrapper.ui';
import styles from './questionnaire.styles';
export default class Questionnaire extends Component {
static propTypes = {
fetchProfile: PropTypes.func.isRequired,
index: PropTypes.number.isRequired, // 0-based question index
isLastQuestion: PropTypes.bool.isRequired,
nextScene: PropTypes.string.isRequired,
questionCount: PropTypes.number.isRequired,
questions: PropTypes.arrayOf(QuestionWrapper.propTypes.question).isRequired,
saveAnswers: PropTypes.func.isRequired,
setCompleted: PropTypes.func.isRequired,
setIndex: PropTypes.func.isRequired,
updateAnswer: PropTypes.func.isRequired,
userId: PropTypes.number.isRequired,
answers: PropTypes.shape({}),
currentCategoryTitle: PropTypes.string,
isDemo: PropTypes.bool,
prompt: PropTypes.string,
};
static defaultProps = {
answers: {},
currentCategoryTitle: '', // may be blank if user logs out here
isDemo: false,
prompt: '', // may be blank if user logs out here
};
constructor(props) {
super(props);
this.state = {
currentOffset: 0,
currentIndex: props.index, // 0-based question index
isModalVisible: false,
};
}
componentDidMount() {
this.scrollToCurrentQuestion(); // ios only. for android it must be called after ScrollView render animation.
this.previousStatusBarStyle = StatusBar._defaultProps.barStyle.value;
StatusBar.setBarStyle('light-content');
if (Platform.OS !== 'ios') {
AndroidKeyboardAdjust.setAdjustPan();
}
if (this.props.nextScene === ADDRESS_FORM) {
this.props.fetchProfile();
}
}
componentWillUnmount() {
if (!loggingOut) {
StatusBar.setBarStyle(this.previousStatusBarStyle);
}
if (Platform.OS !== 'ios') {
AndroidKeyboardAdjust.setAdjustResize();
}
}
completeQuestionnaire() {
this.props.setCompleted(this.props.userId);
resetScene(this.props.nextScene);
}
hideModal = () => {
this.setState({ isModalVisible: false });
};
showModal = () => {
this.setState({ isModalVisible: true });
};
scrollForward = () => {
this.scrollView.scrollTo({ x: this.state.currentOffset + Dimensions.get('window').width });
if (this.state.currentIndex < this.props.questions.length - 1) {
this.updateIndex(this.state.currentIndex + 1);
}
};
scrollBackward = () => {
this.scrollView.scrollTo({ x: this.state.currentOffset - Dimensions.get('window').width });
if (this.state.currentIndex > 0) {
this.updateIndex(this.state.currentIndex - 1);
}
};
scrollToCurrentQuestion = () => {
if (!this.scrollView) return;
this.scrollView.scrollTo({ x: this.state.currentIndex * Dimensions.get('window').width });
};
updateIndex(index) {
this.setState({ currentIndex: index });
this.props.setIndex(index);
}
updateAnswer = (question, answer, message) => {
const isFinalSubmit = this.props.isLastQuestion || answer === 'Our surrogate';
if (isFinalSubmit) {
this.completeQuestionnaire();
} else {
this.scrollForward();
}
let formattedAnswer = answer;
if (question.type === 'DATE') {
formattedAnswer = new Date(answer).toISOString().substring(0, 10);
} else if (question.type === 'SELECT_MULTIPLE') {
formattedAnswer = answer.join('\t');
}
this.props.saveAnswers([{
questionId: question.id,
value: formattedAnswer,
optionalText: message,
}], isFinalSubmit);
this.props.updateAnswer(question.id, answer);
};
skipQuestionnaire = () => {
if (this.props.isDemo) {
Actions.reset(LOADING_SESSION_SMATTER);
} else {
this.completeQuestionnaire();
// not ideal but have to pass an array of answers to mark questionnaire completed
this.props.saveAnswers([], true);
}
};
handleScroll = (event) => {
this.setState({ currentOffset: event.nativeEvent.contentOffset.x });
};
// not used by any questions (?)
TooltipModal = () => {
const currentQuestion = this.props.questions[this.state.currentIndex];
return (
<Modal
isVisible={this.state.isModalVisible}
backdropOpacity={0.4}
onBackdropPress={this.hideModal}
onBackButtonPress={this.hideModal}
>
<View style={styles.modal}>
<View style={[styles.body, { width: 280 }]} >
<View style={{ margin: 24 }}>
<Text style={styles.question}>{currentQuestion.info ? currentQuestion.info.header : 'None'}</Text>
<Text style={styles.modalText}>{currentQuestion.info ? currentQuestion.info.body : 'None'}</Text>
</View>
<View style={styles.divider} />
<View style={styles.modalFooter}>
<TouchableOpacity style={styles.nextButton} onPress={this.hideModal}>
<Text style={styles.modalDone}>GOT IT</Text>
</TouchableOpacity>
</View>
</View>
</View>
</Modal>
);
};
render() {
if (this.props.questionCount === 0) {
return (
<View style={styles.loading}>
<ActivityIndicator size="large" />
</View>
);
}
return (
<View style={styles.container}>
<QuestionnaireHeader
categoryTitle={this.props.currentCategoryTitle}
onPressSkip={this.skipQuestionnaire}
/>
<ScrollView
horizontal
pagingEnabled
ref={(c) => { this.scrollView = c; }}
showsHorizontalScrollIndicator={false}
onContentSizeChange={this.scrollToCurrentQuestion}
scrollEnabled={false}
onScroll={this.handleScroll}
>
{this.props.questions.map((question, i) => (
<QuestionWrapper
key={question.id}
questionNumber={i + 1}
prompt={this.props.prompt}
question={question}
scrollBackward={this.scrollBackward}
showModal={this.showModal}
updateAnswer={this.updateAnswer}
answers={this.props.answers}
isLastQuestion={this.props.isLastQuestion}
totalQuestions={this.props.questionCount}
/>
))}
</ScrollView>
<this.TooltipModal />
</View>
);
}
}
答案 0 :(得分:0)
根据Tholle的建议,我查看了Questionnaire
的调查表的导入位置,该调查表位于questionnaire.container.js
中,内容为:
import { connect } from 'react-redux';
import { trackEvent } from 'app/src/lib/analytics';
import { ADDRESS_FORM, NOTIFICATION_PERMISSIONS } from 'app/src/scenes';
import { fetchProfile } from 'app/src/containers/profile/profile.actions';
import { logOut } from 'app/src/containers/login/login.actions';
import { saveAnswers, setCompleted, setIndex, updateAnswer } from './questionnaire.actions';
import { getQuestionSet, getCurrentQuestion, getCurrentQuestionPrompt } from './questionnaire.selectors';
import Questionnaire from './questionnaire.ui';
const mapStateToProps = (state) => {
const { user } = state;
const { questionnaire } = user.onboarding;
const { categories } = questionnaire;
const questions = getQuestionSet(state);
const currentIndex = questionnaire.index;
const question = getCurrentQuestion(state);
const currentCategory = question && categories.find(category => category.id === question.categoryId);
const isLastQuestion = currentIndex === questions.length - 1;
return {
questions,
question,
categories,
currentIndex,
isLastQuestion,
answers: questionnaire.answers,
index: questionnaire.index, // 0-based index
nextScene: questionnaire.hasShortEnrollment ? ADDRESS_FORM : NOTIFICATION_PERMISSIONS,
isDemo: user.login.isDemo,
prompt: getCurrentQuestionPrompt(state),
answer: question && questionnaire.answers[question.id],
questionCount: questions.length,
currentCategoryTitle: currentCategory && currentCategory.title,
loading: questionnaire.loading,
userId: user.login.user && user.login.user.id,
};
};
const mapDispatchToProps = dispatch => ({
saveAnswers: (answers, isFinalSubmit) => {
dispatch(saveAnswers(answers, isFinalSubmit));
},
setCompleted: (userId) => {
trackEvent(userId, 'Completed Questionnaire');
dispatch(setCompleted());
},
setIndex: (index) => {
dispatch(setIndex(index));
},
updateAnswer: (questionId, answer) => {
dispatch(updateAnswer(questionId, answer));
},
logOut: () => {
dispatch(logOut());
},
fetchProfile: () => {
dispatch(fetchProfile());
},
});
export default connect(
mapStateToProps,
mapDispatchToProps,
)(Questionnaire);
实际上,Questionnaire
也可以通过将其传递到connect()
来呈现,不仅是将其括在<Questionnaire>
之类的三角括号中。