Рендеринг массива с помощью React Async не определен

#javascript #reactjs #react-redux #redux-thunk

#javascript #reactjs #react-redux #redux-thunk

Вопрос:

Я извлекаю данные из службы REST. Данные возвращаются в виде массива. Это функция, которую я использую для извлечения данных.

 export function fetchMessage() {
  return function(dispatch) {
    axios.get(`${ROOT_URL}/currencies`, {
      headers: { token: localStorage.getItem('token') }
    })
     .then(response => {
       console.log(response.data);
       dispatch({
         type: FETCH_MESSAGE,
         payload: response.data
       });
     });
  }
}
  

Результатом fetchMessage является массив объектов.

 [Object, Object, Object, Object, Object, Object]
0:Object
    addedDate:"2013-08-22"
    ccyCode:"CHF"
    country:"SCHWIZER FRANC"
    lastChangeDate:"2016-05-02"
    offerRate:7.02
    prevRate:8.501
    prevRateDate:"2016-04-01"
    rate:8.425
    rateDate:"2016-05-01"
    unit:1
    __proto__:Object
1:Object
2:Object
3:Object
4:Object
5:Object
  

fetchMessage Функция вызывается компонентом, указанным ниже.

 class Feature extends Component {
  componentWillMount() {
    this.props.fetchMessage();
    //console.log(this.props);
  }

  render() {
    return (
      <div>{this.props.message}</div>
    );
  }
}

function mapStateToProps(state) {
  return { message: state.auth.message };
}

export default connect(mapStateToProps, actions)(Feature);
  

Компонент не может отобразить сообщение, потому что это

 bundle.js:1256 Uncaught (in promise) Error: Objects are not valid as a React child (found: object with keys {ccyCode, country, unit, rateDate, rate, prevRateDate, prevRate, offerRate, addedDate, lastChangeDate}). If you meant to render a collection of children, use an array instead or wrap the object using createFragment(object) from the React add-ons. Check the render method of `Feature`.(…)
  

Я пытался запустить карту this.props.message , подобную этой

 <div>
        {this.props.message.map(
          function(object){
            return ('Something'
            );
          }
        )}
</div>
  

Но я получаю сообщение об ошибке, в котором говорится, что я не могу работать map дальше message . Как я могу отобразить данные в объекте? Нужно ли мне сохранять его каким-либо другим способом? Как мне перебирать объекты для их рендеринга?

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

1. Попробуйте что-то вроде этого: <div>{this.props.message.ccyCode} {this.props.message.rate}</div> и переходите оттуда.

2. @ChrisG Я пробовал оба <div>{this.props.message.ccyCod}</div> , <div>{this.props.message.rate}</div> и оба выдают сообщение об ошибке Uncaught TypeError: Cannot read property 'rate' of undefined с неопределенным свойством, которое, конечно, изменится ccyCode , когда я попытаюсь ccyCode .

Ответ №1:

Обновление: я думаю, что ваша проблема заключается только в том, что this.props.message она не определена при первоначальном рендеринге. Попробуйте рендеринг null , если он не установлен.

 render() {
  if (!this.props.message) return null
  return (
    <div>
      {this.props.message.map(message => {
        return (
          <div key={message.ccyCode}>...
            {message.ccyCode} {message.rate} ...
          </div>
        )
      })}
    </div>
  )
}
  

Мой ответ ниже все еще может быть полезен, если кто-то заинтересован в динамическом рендеринге объекта.

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

Попробуйте выполнить итерацию Object.keys и отобразить данные.

 <div>
    {Object.keys(this.props.message).map(key => {
        return (
          <div key={key}> // you need a dynamic, unique key here to not get a React warning
            {key}: {this.props.message[key]}
          </div>
        )
      }
    )}
</div>
  

Если вы хотите просто показать данные для целей отладки / проверки, я обнаружил, что это очень полезно.

 <pre>
  {JSON.stringify(this.props.message,null,2)}
</pre>
  

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

1. Спасибо за предложения, Брэд. Строка JSON отображает весь объект. Но когда я пробую Object.keys настройку <div key={ccyCode}> , то получаю ReferenceError: ccyCode , что она не определена. Я не понимаю, что вы подразумеваете под «неопределенным при первоначальном рендеринге»? Есть ли второй рендеринг? Использование оператора if, я думаю, просто приведет к отображению nothing / null?

2. Во-первых, где это ccyCode определено? Обычно вы используете значение из сопоставленной записи. Так что вам, возможно, просто нужно сослаться на него this.props.message[key].ccyCode следующим образом. Во-вторых, поскольку вы вызываете асинхронный API componentWillMount() , он будет отображаться сначала без данных, а затем во второй раз, когда ответ обновит состояние.

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

4. Спасибо, Брэд. Я изменил на `<div key={this.props.message[key].ccyCode}> {key}: {this.props.message[key].ccyCode} </div>`, который выдает 0: CHF 1: DKK 2: EUR... именно то, что я хочу. Всего один вопрос, с которым я задаю свой ключ, key={this.props.message[key].ccyCode} но затем, когда я использую `{key}`, выводится число. Чего мне не хватает в моем понимании?

5. Сложно сказать .. вы хотите динамически перебирать все поля объекта или все объекты в массиве? Используете ли вы Object.keys по-прежнему только карту?