2016-09-19 2 views
2

У меня есть ощущение, что это «неправильно» задать вопрос, но здесь идет так или иначе:Убедитесь, новый экземпляр определенного компонента используется

Делаю какое-то викторина приложения (используя Redux для государства управление). (Показывая важные биты здесь)

quiz.js

<Slider {...sliderSettings} slideIndex={currentQuestionIndex}> 
    <Start onStart={() => onNextQuestion()} topicId={topicId} /> 

    { 
     questions.map((question, ndx) => { 
      return (
       <Question {...question} done={onDone} key={`question-${question.id}`} /> 
      ); 
     }) 
    } 

    <Result score={score} onRestart={() => onRestart()}/> 
</Slider> 

question.js

<div className="question"> 
    <h2 className="question__text">{ question }</h2> 
    <MultipleChoice options={answers} onChange={done} /> 
</div> 

множественные-choice.js

const 
    initialState = { 
     selectedValue: null 
    }; 

class MultipleChoice extends Component { 
    constructor(props) { 
     super(props); 
     this.state = initialState; 
    } 

    handleChange(value, correct) { 
     this.setState({ 
      selectedValue: value 
     }); 

     this.props.onChange(correct); 
    } 

    render() { 
     const 
      { options } = this.props, 
      getStateClass = (option, ndx) => { 
       let sc = ''; 

       if (this.state.selectedValue !== null) { 
        if (this.state.selectedValue === ndx) { 
         sc = option.correct ? 'is-correct' : 'is-incorrect'; 
        } else if (option.correct) { 
         sc = 'is-correct'; 
        } 
       } 

       return sc; 
      }; 

     return (
      <ul className="multiple-choice"> 
       { options.map((option, ndx) => { 
        return (
         <li key={`option-${ndx}`} className={cx('multiple-choice__option', getStateClass(option, ndx))}> 
          <button className="multiple-choice__button" onClick={() => this.handleChange(ndx, option.correct)}>{option.answer}</button> 
         </li> 
        ); 
       }) } 
      </ul> 
     ); 
    }; 
} 

export default MultipleChoice; 

Проблема заключается в оказании Большой выбор. Он использует внутреннее состояние, чтобы показать, какой ответ неправильный и правильный.

in quiz.js, onRestart отправляет редукционное действие, которое обновляет хранилище, чтобы получить новые вопросы и сбросить currentQuestionIndex на 0. Это все работает. Но почему-то иногда элемент MultipleChoice «повторно используется» и по-прежнему показывает состояние, которое он имел в предыдущем раунде вопросов. Другими словами, большую часть времени монтируется новый MultipleChoice, но иногда это не так. Это реакция примирения, если я правильно понимаю?

Но как решить эту проблему? На мой взгляд, MultipleChoice нуждается в его внутреннем состоянии. Так что я должен как-то сбросить это состояние? Или убедитесь, что новый MultipleChoice монтируется каждый раз? Или я задаю здесь неправильные вопросы?

ответ

15

Я смотрел на your repository, и вопрос, как правильно noted in another answer является то, что ваши <Question> (и, таким образом, внутренние <MultipleChoice>) компоненты не никогда размонтировать, поэтому они сохраняют свое состояние.

Обычно это не часто возникает в реактиве, потому что люди обычно хотят сохранить состояние, пока компонент находится в дереве. Когда состояние больше не требуется, люди обычно останавливают включение компонентов в методе render(), а React отключает их. В следующий раз, когда они отображаются, их состояние сбрасывается.

Государство делает не получить сброс в вашем примере, потому что вы всегда держать <Question> с видимым, даже между пробегами викторины.Вы можете видеть, что <Question> s уже установлены, прежде чем начать тест, и оставаться смонтированный после его окончания:

stale-questions

Так как мы можем принудительно Реагировать сбросить их состояние? Существует три варианта:

  • Вы можете заставить их размонтировать. В следующий раз, когда они будут установлены, у них будет новое состояние. Это, как правило, самое простое решение, потому что вы фактически не отображаете вопросы на начальной странице «начать викторину». Например, вы можете сделать это, добавив currentQuestionIndex > 0 && охрану перед рендерингом questions.map(...) в render() методе <Questions>.

  • Вы можете передать новые key s им, которые не соответствуют предыдущим key s. В настоящее время вы используете question-${question.id} как key, но это будет производить тот же ключ для того же вопроса, даже если вы повторите тест. Чтобы решить эту проблему, вы можете ввести новую переменную состояния (либо в Redux, либо в состояние компонента верхнего уровня), например quizAttemptIndex, и увеличить ее при любой новой попытке. Затем вы можете изменить ключ на question-${quizAttemptIndex}-${question.id}. Таким образом, попытка опроса в другое время сбрасывает внутреннее состояние вопроса (а также вызывает его повторное подключение).

  • Наконец, если вы не хотите уничтожить DOM полностью, передавая различные key, вы могли бы пройти quizAttemptIndex (описано в предыдущем разделе) в качестве опоры для <MultipleChoice>. Затем, внутри него, вы можете this.setState({ selectedValue: null }) внутри componentWillReceiveProps(nextProps) если nextProps.quizAttemptIndex !== this.props.quizAttemptIndex.

Вы можете выбрать любое решение в зависимости от того, насколько важно, чтобы вы постоянно задавали вопросы.

0

Насколько я понял, вы хотите, чтобы ваш компонент MultipleChoice обновил его состояние, когда вы хотите, чтобы это было сделано. Но поскольку вы используете состояние реакции в своем компоненте, пока ваш компонент не отключается, ваше состояние реакции в вашем MultipleChoice сохраняет свое последнее состояние.

Такое поведение ожидается от состояния реакции, потому что в основном вы хотите использовать его для внутреннего поведения. Возможно, вы хотите переключить некоторые данные ui в свой компонент, когда какая-то кнопка или что-то заставляет ваш компонент делать это. Или вы хотите контролировать свои формы ввода и т. Д.

Но то, что вы ожидаете, должно быть выполнено в состоянии redux. Ваш компонент должен быть повторно использован, который не заботится о том, где он установлен. Вы передаете свои данные, связанные с монтированием, в свой MultipleChoice с помощью реквизита, который берется из redux. Итак, теперь у вас есть многоразовый компонент. Не тратьте много времени на монтаж и т. Д. Вы можете проверить хранилища регрессионных репозиториев на github, чтобы ознакомиться с тем, как формировать поток данных вашего проекта. Когда следует использовать состояние redux, чтобы вызывать отклонения или обрабатывать состояние в своем компоненте по состоянию реакции.

+0

вы правильно поняли думаю. Я уже думал о предложенном вами решении, но для меня это довольно странно. Теперь я остаюсь с чувством: «Если это не относится к внутреннему состоянию, то что?» – ThomasM

Смежные вопросы