Слияние версий с несколькими состояниями для React

#javascript #reactjs #meteor

#javascript #reactjs #метеор

Вопрос:

У меня есть одно состояние внутри моего компонента React, которое имеет такую структуру {a: {x: 0}, b: {x:0}} . Во время работы мне нужно запустить несколько запросов к серверу, чтобы запросить данные для обновления состояния, и это необходимо обновить в состоянии. Поскольку номер записи в базе данных довольно большой, мне приходится запускать несколько раз

Если мне это нравится

 request_data(e) {
   ['a', 'b'].forEach((k) => {
      // do not mutate the state directly
      let new_state = _.extend({}, state);

      request(params, (err, res) => {
         // set result to the new_state 
         new_state = res; 
         // update the original state
         this.setState(newState);
      })
   });
}
  

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

Одним из простых решений является прямое обновление исходного состояния, но я не думаю, что это хорошая идея. Я планирую интегрировать redux позже, но на данный момент, поскольку текущая база кода довольно большая, лучше выполнять постепенную миграцию. Однако я не хочу напрямую изменять исходное состояние, поскольку это не redux так. Есть предложения по преодолению этой проблемы?

Комментарии:

1. Что вы делаете внутри метода жизненного цикла компонента React? Где находится этот код?

2. В данный момент я обновляю свое приложение из Blaze до React, и часть его все еще находится внутри Blaze. Фактический код довольно сложный ReactiveVar , в том числе и для meteor, но предположим, что этот код находится внутри компонента React. Я не вижу никакой разницы, поскольку это общая проблема объединения нескольких копий состояния во время обратных вызовов

Ответ №1:

Я предполагаю, что, судя по тому, как написан ваш код, вы используете классы es6 для своего компонента? В таком случае, надеюсь, этот лакомый кусочек поможет:

 import React from 'react'

class MyComponent extends React.Component {
  constructor(props) {
    super(props)

    this.state = {
      foo:'bar'
    }
  }

  request_data = (e) => {
    ['a', 'b'].forEach((k) => {
      // do not mutate the state directly
      let new_state = _.extend({}, state);

      request(params, (err, res) => {
         // set result to the new_state 
         // update the original state
         this.setState(foo:res.foo)
      })
    });
  }

  render() {
    return (
      // component code here
    )
  }
}

export default MyComponent
  

Обратите внимание, что я использую функцию со стрелкой для части request_data…это делается для того, чтобы избежать необходимости привязывать функцию к this переменной внутри конструктора.

Обновить:

Я все еще не совсем уверен, что понимаю, с какой проблемой вы столкнулись здесь … но если вы не хотите использовать redux прямо сейчас, вы можете использовать метод компонента контейнера. По сути, основная задача вашего компонента контейнера — управлять данными и ничего не делать, кроме как передавать его обновленное состояние дочернему компоненту в качестве реквизита. Что-то вроде этого:

 class MyComponentContainer extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      a: {
        x: 0
      }, 
      b: {
        x:0
      }
    }
  }

  componentWillMount() {
     ['a', 'b'].forEach((k) => {
        request(params, (err, res) => {
           this.setState({
            a: res.a,
            b: res.b
           });
        })
     });
  }

  render() {
    return (
      <MyComponent data={this.state} />
    )
  }
}

class MyComponent extends React.Component {
  constructor (props) {
    super(props)
  }

  render() {
    return (
      <div>
        {/* display stuff here */}
      </div>
    )
  }
}

export default MyComponentContainer
  

Комментарии:

1. Пожалуйста, внимательно прочитайте мой вопрос. Я знаю, что могу напрямую изменять исходное состояние, но я не думаю, что это хорошая идея. Поскольку позже я мог бы интегрироваться с redux , и я не хочу снова менять свой код с помощью immutablejs

2. Использование setState не изменяет состояние напрямую. Когда вы начнете использовать redux, вы сможете создавать новые объекты состояния либо с помощью Object.assign, либо _.extend, либо с помощью оператора распространения, как вам заблагорассудится. В этом случае вы находитесь внутри компонента, который предоставляет вам метод setState и не изменяет состояние напрямую. Это метод, который компоненты React предоставили для обновления состояния.

3. если вы говорите об этом.state = {} в конструкторе, это не обновление состояния, а установка его начального значения. Мы говорим здесь о состоянии компонента, верно?

4. Привет, Майк, я пытаюсь использовать new_state внутреннюю функцию для ввода this.setState . Позже я использую визуализацию redux , код будет примерно таким в редукторах: new_state = Object.assign({}, state); return new_state; , и если мой текущий код уже справляется с immutablejs проблемой, мне не нужно думать о логике позже

5. Итак, вы хотите изменить состояние напрямую? На мой взгляд, я бы все равно использовал redux здесь, поскольку вы все равно планируете использовать его в будущем, и просто используйте redux для компонентов React, на которые вы переходите. Вы можете постепенно создавать новые редукторы по мере необходимости, и вы можете использовать redux только для тех компонентов, которые вам нужны. Другими словами, вы все равно можете использовать redux, даже если вы постепенно переходите.