H
H
hiPaul2019-10-01 16:58:51
Arrays
hiPaul, 2019-10-01 16:58:51

Mobx array state update in React Native?

The store stores an array of objects with questions, I'm trying to add a new property to the object with the user's answer, but mobX swears at the side effect that I change the state of the array in the renderer.
Stour himself:

class TestStore {
  @observable questionsArray;
  @observable currentQuestionIndex;

  constructor() {
    this.questionsArray = stub;
    this.currentQuestionIndex = 0;
  }

  @computed get questionsArrayLength() {
    return this.questionsArray.length;
  }

  @computed get currentQuestion() {
    return this.questionsArray[this.currentQuestionIndex];
  }

  @action setUserAnswer = answer => {
    this.questionsArray[this.currentQuestionIndex] = {
      ...this.currentQuestion,
      userAnswer: answer
    };
  }

  @action setCurrentQuestionIndex = index => {
    if (index > 0 && index < this.questionsArray.length) {
      this.currentQuestionIndex = index;
    }
  }
}

The error comes with the action setUserAnswer
Controller:
@inject("testStore")
@observer
export default class QuestionsScreen extends React.Component {
  handleFirstPress = (answer) => {
    const {
      testStore: { setUserAnswer }
    } = this.props;
    setUserAnswer(answer);
  };

  handleSecondPress = () => {
    const {
      testStore: {
        currentQuestionIndex,
        setCurrentQuestionIndex,
        currentQuestion: { userAnswer }
      }
    } = this.props;
    if (!userAnswer) {
      return;
    }
    setCurrentQuestionIndex(currentQuestionIndex + 1);
  };

  render() {
    const {
      testStore: {
        currentQuestion,
        currentQuestionIndex,
        questionsArrayLength,
        // setUserAnswer
      }
    } = this.props;

    return (
      <TouchableWithoutFeedback onPress={this.handleSecondPress}>
        <View style={styles.container}>
          <View style={{ width: "100%" }}>
            <Text>{`Вопрос №${currentQuestionIndex + 1}`}</Text>
            <HorisontalList
              values={this.getButtonsList(questionsArrayLength)}
            />
            <QuestionsWithAnswers
              question={currentQuestion.question}
              answers={shuffleArray(currentQuestion.answers)}
              right={currentQuestion.right}
              userAnswer={currentQuestion.userAnswer}
              onFirstPress={this.handleFirstPress}
              onSecondPress={this.handleSecondPress}
            />
          </View>
          <TouchableOpacity style={styles.describeButton}>
            <Text style={styles.buttonText}>Обсуждение вопроса</Text>
            <Text style={styles.buttonSubText}>3 комментария</Text>
          </TouchableOpacity>
        </View>
      </TouchableWithoutFeedback>
    );
  }
}

And the view component where the handler is called
export default function QuestionsWithAnswers({
  answers = [],
  right,
  question,
  isExam,
  onFirstPress,
  onSecondPress,
  userAnswer
}) {
  const [isFavorite, setFavorite] = useState(false);

  const handlePressButton = (selectedItem) => {
    if (isExam) {
      // логика при экзамене
    } else {
      // логика при тренировке
      if (!userAnswer) {
        onFirstPress(selectedItem);
      } else {
        onSecondPress();
      }
    }
  }

  return (
    <View style={styles.container}>
      <View
        style={{
          flexDirection: "row",
          justifyContent: "space-between",
          alignItems: "center",
          width: "90%" //moment so interesting
        }}
      >
        <Text style={styles.text}>{question}</Text>
        <Text style={{ fontSize: 40 }} onPress={() => setFavorite(!isFavorite)}>
          {isFavorite ? "★" : "☆"}
        </Text>
      </View>
      {answers.map((el, index) => (
        <TouchableOpacity
          key={index}
          onPress={() => handlePressButton(el)}
          style={[
            styles.listItem,
            { backgroundColor: getAnswerBackgroundColor(el) }
          ]}
        >
          <Text>{el}</Text>
        </TouchableOpacity>
      ))}
    </View>
  );
}

Help =)

Answer the question

In order to leave comments, you need to log in

1 answer(s)
0
0xD34F, 2019-10-02
@hiPaul

swears at the side effect that I change the state of the array in the renderer

There is some suspicious code inside the only render you showed:
Probably, shuffleArray modifies the passed array, and does not create a new one. Well, try creating your own:
answers={shuffleArray([...currentQuestion.answers])}

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question