How to get a user’s choice with onPress props in R

2019-08-28 17:46发布

Good day everyone. please what is React Native’s replacement of React’s e.target.innerText? I’m trying to get what a user click on from TouchableOpacity component. I’m building a React Native quiz app.

I used TouchableOpacity for the options. I’m using onPress function to get the options the user clicks on with

<View style={{ flex: 2, flexDirection: 'row', justifyContent: 'space-between' }}>
                    <TouchableOpacity onPress = {(e)=>this.props.onAnswer(e, currentQuestion)}>
                        <View style={{ width: 171.5, height: 100, backgroundColor: 'lightgrey' }}>
                            <Text style={styles.options}>{questions[currentQuestion].options[0]}</Text>
                        </View>
                    </TouchableOpacity>
                    <TouchableOpacity onPress = {(e)=>this.props.onAnswer(e, currentQuestion)}>
                        <View style={{ width: 171.5, height: 100, backgroundColor: 'lightgrey' }}>
                            <Text style={styles.options}>{questions[currentQuestion].options[1]}</Text>
                        </View>
                    </TouchableOpacity>
                </View>
                <View style={{ flex: 2.7, flexDirection: 'row', justifyContent: 'space-between' }}>
                    <TouchableOpacity onPress = {(e)=>this.props.onAnswer(e, currentQuestion)}>
                        <View style={{ width: 171.5, height: 100, backgroundColor: 'lightgrey' }}>
                            <Text style={styles.options}>{questions[currentQuestion].options[2]}</Text>
                        </View>
                    </TouchableOpacity>
                    <TouchableOpacity onPress = {(e)=>this.props.onAnswer(e, currentQuestion)}>
                        <View style={{ width: 171.5, height: 100, backgroundColor: 'lightgrey' }}>
                            <Text style={styles.options}>
                                {questions[currentQuestion].options[3]}
                            </Text>
                        </View>
                    </TouchableOpacity>
                </View>

So creating the answer function ... how do I determine if the user has chosen the correct answer.

onAnswer = () => {
        return (
            ??? === questions[currentQuestion].answer ? this.onCorrect() : this.onWrong()
          )
        }


If it was React,I'd have replaced the '???' to e.target.innerText

Please help me out here.

2条回答
Evening l夕情丶
2楼-- · 2019-08-28 18:21

Try this:

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

const questions = [
  {
    question: 'question1 ?',
    options: ['option1', 'option2', 'option3'],
    answer: 'option2',
    score: 10,
  },
  {
    question: 'question2 ?',
    options: ['option1', 'option2', 'option3'],
    answer: 'option1',
    score: 10,
  },
  {
    question: 'question3 ?',
    options: ['option1', 'option2', 'option3'],
    answer: 'option3',
    score: 10,
  },
];

class QuizQuestion extends React.Component {
  constructor(props) {
    super(props);

    this.state = {
      totalScore: 0,
      answered: questions.map(() => false), // All questions' answered state = false at statup
    };
  }

  render() {
    return (
      <View
        style={{
          flex: 2,
          flexDirection: 'row',
          justifyContent: 'space-between',
        }}
      >
        {questions.map(({
          question, options, answer, score,
        }, index) => (
          <View>
            <View>
              <Text>{question}</Text>
            </View>

            {/* Options  */}
            <View>
              {options.map(({ option }) => (
                <TouchableOpacity
                  onPress={() => {
                    let { totalScore, answered } = this.state;

                    if (!answered[index] && option === answer) {
                      answered[index] = true;
                      this.setState({
                        totalScore: totalScore + score,
                        answered,
                      });
                    }
                  }}
                >
                  <View>
                    <Text>{option}</Text>
                  </View>
                </TouchableOpacity>
              ))}
            </View>
          </View>
        ))}
      </View>
    );
  }
}
查看更多
爷、活的狠高调
3楼-- · 2019-08-28 18:27

EDIT:

My original answer below is similar to what you have. So just simply edit your onPress method like this:

onPress = {(e)=>this.props.onAnswer(currentQuestion, questions[currentQuestion].options[0])}

and your onAnswer will be able to take the users answer per questions:

onAnswer(question, usersAnswer) {
  ..
}

render() { ... }

**


Mostly, react components should be driven by data or states and props (you don't want to work with your logic by relying to DOM elements with pure JS or JQuery).

For that, you want a react solution like below:

...
  state = {
    data: [{
      id: 1,
      name: 'Anna'
    },
    {
      id: 2,
      name: 'John'
    },
    {
      id: 3,
      name: 'James'
    },
    {
      id: 4,
      name: 'John'
    }]
  }
  onPersonPress(person) {
    console.log("e is ", person);
  }

  render() {
    const { data = [] } = this.state;
    return (
      <View>
        {data.map(person => {
          return (<TouchableOpacity onPress={(e) => this.onPersonPress(person)}>
            <View><Text>Click Me - {person.name}</Text></View>
          </TouchableOpacity>)
        })}
      </View>
    )
  }
  ...

The reason why this is the most common way to deal with this kind of problem is because of it's flexibility and probably it's the most logical. With this, you can use the identifier (id) or any field instead of being forced to what Text displays 'innerText' which isn't always unique (in my case there's another John)

P.S: Others don't like this implementation because of performance considerations onPress={(e) => this.onPersonPress(person)} so there are other ways to achieve the same.

查看更多
登录 后发表回答