Как объединить элемент в последний массив внутри корневого массива?

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

При повторном нажатии кнопки прослушиватель будет удален. Пользователь может нажать кнопку и снова начать слушать новый набор координат. Они могут делать это неоднократно.

this.state = {
    pathArray: [], // originally a 1D array, should become 2D as user keep using the app
    pathCount: 0,
}

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

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

pathArray = [
    [ 
        { lat: 0, long: 0 },
        { lat: 1, long: 2 },
    ],
    [ 
        { lat: 0, long: 0 },
        { lat: 1, long: 2 },
    ],
]

onButtonPressed = () => {
    const { running } = this.state
    if (!this.state.running) {
      this.followWatchCoords() // start collecting data
    } else {
      this.stopFollowing() //stop collecting data
    }
  }

followWatchCoords = () => {
    this.followUserWatchID = navigator.geolocation.watchPosition(({ coords }) => {
    
      this.calculateDistance(coords)

    }, null, GEOLOCATION_SETTINGS)
  }

calculateDistance = (coords) => {
    const { latitude, longitude } = coords

    const positionLatLong = pick(coords, ['latitude', 'longitude'])

    let newArr = this.state.pathArray.slice(); //copy array to mutate
    newArr.push(positionLatLong)


    this.setState({
      pathArray: newArr,
    })
  }


person J.Doe    schedule 30.05.2017    source источник
comment
Так в чем вопрос?   -  person Chris    schedule 30.05.2017
comment
Как я могу создать новый массив внутри корневого массива при нажатии кнопки и продолжать добавлять объекты в дочерний массив до тех пор, пока кнопка не будет нажата снова. Если кнопка нажата снова, новый дочерний массив будет создан снова, и процесс будет продолжаться и дальше.   -  person J.Doe    schedule 30.05.2017
comment
Эта кнопка запускает повторяющийся процесс, когда запись выполняется каждые X секунд, пока кнопка не будет нажата снова?   -  person Chris    schedule 30.05.2017
comment
по сути, кнопка запускает другую функцию (приемник GPS), и именно здесь я манипулирую массивами. Да, ты понял @Chris   -  person J.Doe    schedule 30.05.2017
comment
Чтобы создать новый массив в конце списка: pathArray.push([]). Чтобы добавить элементы в этот вновь созданный массив: pathArray[pathArray.length - 1].push({lat: 1, long: 2}).   -  person abhishekkannojia    schedule 30.05.2017
comment
@abhishekkannojia reactjs не позволяет мне сделать pathArray[pathArray] в блоке setState...   -  person J.Doe    schedule 30.05.2017


Ответы (2)


Ниже простой фрагмент того, как вы могли бы реализовать это.

В основном, порядок событий таков:

  1. Щелчок по кнопке запускает функцию _startStop(), которая запускает интервал.
  2. Интервал извлекает координаты широты/долготы из поддельного API GPS каждые 3000 мс.
  3. Новые координаты помещаются в массив состояний.

При повторном нажатии на кнопку срабатывает та же функция, но интервал сбрасывается и процесс останавливается.

class MyApp extends React.Component {
  constructor() {
    super();
    this.interval;
    this.state = {arr: []};
    this._getFakeCoords = this._getFakeCoords.bind(this);
    this._startStop = this._startStop.bind(this);
  }
  
  _getFakeCoords() {   
    return {lat: Math.random() * 100, long: Math.random() * 100};
  }
  
  _startStop() {
    if(this.interval) {
      clearInterval(this.interval);
      this.interval = null;
    } else {
      let newArr = this.state.arr.slice();  //copy the array so we can mutate it
      this.interval = setInterval(() => {
        newArr.push([this._getFakeCoords(), this._getFakeCoords()]);
        this.setState({arr: newArr});  //replace the old array with the mutated one
        console.log(newArr);  //preview the result
      }, 3000);
    }
  }
  
  render() {
    return (
      <div>
      	<button onClick={this._startStop}>Start/Stop</button>
      </div>
    );
  }
}

ReactDOM.render(<MyApp />, document.getElementById("app"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="app"></div>

person Chris    schedule 30.05.2017
comment
Кажется выполнимым, но 2 вещи. Во-первых, библиотека геолокации публикует новые данные каждые несколько миллисекунд, поэтому функция setInterval, вероятно, здесь не пригодится. Компонент, который я использовал для рендеринга строк, использует 1 массив объектов для рендеринга 1 строки. 2 объекта = 1 строка, несколько объектов (в 1 массиве) = 1 очень длинная строка. Так что в идеале, если мой pathArray имеет 2 дочерних массива, мы должны ожидать 2 строки. - person J.Doe; 30.05.2017
comment
Только что попробовал ваш подход, но он не соответствует моим требованиям, ха-ха, позвольте мне обновить мой пост с моим текущим кодом - person J.Doe; 30.05.2017
comment
@ J.Doe, хорошо, но это всего лишь доказательство концепции. Не полное решение. Если ваш API работает по-другому, просто измените код соответствующим образом. Я предполагаю, что вопрос здесь будет заключаться в том, как преобразовать массив или что-то еще. Просто обновите эту часть - т.е. как сначала выглядит массив и как должен выглядеть результат. Я обновлю только эту часть. - person Chris; 30.05.2017
comment
Я обновил пост своим кодом, так как вы можете видеть, что функция calculateDistance будет обновляться каждый раз, когда библиотека геолокации собирает новые данные. - person J.Doe; 30.05.2017
comment
@ Джей Доу, хорошо. Я не вижу проблемы с массивом 1D -> 2D. В этом проблема, верно? - person Chris; 30.05.2017
comment
Ха-ха, чувак, calculateDistance будет выполняться, возможно, тысячи раз для каждого сеанса кнопки. Хитрость этой проблемы заключается в том, что новые данные всегда будут добавляться в конец списка. Итак, возможно, мы можем создать пустой массив при первом нажатии кнопки, а затем добавить данные в последний дочерний элемент массива?? хм - person J.Doe; 30.05.2017
comment
@ J.Doe, вы плохо объясняете свою проблему, и у вас есть куча кода, который не имеет отношения к проблеме программирования, о которой вы спрашиваете. Это затрудняет понимание другими, потому что вы объясняете все свое приложение, а не конкретную проблему ... в любом случае, если я правильно понимаю, вы, возможно, могли бы использовать два массива - один для pathArray и другой tempArray. tempArray начинает заполняться координатами, когда вы нажимаете кнопку, чтобы начать, а когда вы останавливаетесь, вы нажимаете tempArray в pathArray? - person Chris; 30.05.2017
comment
Я принимаю вашу критику и буду работать над моей проблемой доставки. Мой компонент должен получить доступ к последнему дочернему массиву в режиме реального времени. Поэтому, если мы поместим tempArray в pathArray только после того, как кнопка будет снова нажата, тогда будет упущена суть, потому что моему приложению нужно рисовать путь в реальном времени :( - person J.Doe; 30.05.2017
comment
логика кажется правильной, но когда я нажимаю новый массив, он возвращает индекс 1, затем я пытался вставить данные в массив, который показывает «Невозможно прочитать свойство «push» неопределенного» - person J.Doe; 30.05.2017
comment
Давайте продолжим обсуждение в чате. - person Chris; 30.05.2017

Наконец-то разобрались после полезного совета, данного Крисом

В моей функции кнопки я создаю новый дочерний массив каждый раз, когда он вызывается

this.setState({
    routeCoordinates: this.state.routeCoordinates.concat([[]]), //add array
    routeCount: this.state.routeCount + 1
})

также увеличивайте routeCount на единицу каждый раз, когда нажимается кнопка (изначально -1 из-за характера массива)

Затем в прослушивателе GPS, поскольку функция calculateDistance будет вызываться каждый раз, когда поступают новые данные, нам просто нужно сделать следующее:

let newArr = [...routeCoordinates]
newArr[routeCount].push(positionLatLong)

this.setState({ routeCoordinates: newArr })

Хитрость заключается в том, чтобы использовать concat и толкать с умом

person J.Doe    schedule 30.05.2017
comment
Рад, что вы нашли решение. Вы должны принять свой собственный ответ и подумать о том, чтобы проголосовать за мой, если вы нашли его полезным. Спасибо. - person Chris; 31.05.2017
comment
Конечно! Приму мой ответ через 2 дня (ограничение SO) - person J.Doe; 31.05.2017