Выполнение вызова axios в режиме рендеринга ничего не возвращает

#javascript #react-native #axios #jsx

Вопрос:

Я делаю вызов axios в рендеринге моего родного приложения react.

 render() {
    return (
      <View style={{flex: 1, backgroundColor: 'white'}}>
        <ScrollView
          style={styles.scrollView}
          contentContainerStyle={{justifyContent: 'center'}}>
          <Text style={styles.heading}>Checked Out Books</Text>
          {this.state.books.map((book) => {
            axios
              .get('http://localhost:3000/books/id/'   book)
              .then((res) => {
                console.log(res.data);
                return (
                  <View>
                    <Image
                      source={{uri: res.data.cover}}
                      height={150}
                      width={110}></Image>
                    <Text>{res.data.title}</Text>
                  </View>
                );
              })
              .catch((err) => {
                console.log(err);
                alert('Something went wrong.');
              });
          })}
 

Когда вызов завершается и он переходит к шагу возврата, ничего не возвращается.

Я не знаю, почему это происходит. Этот сегмент кода не возвращается:

 <View>
  <Image
      source={{uri: res.data.cover}}
      height={150}
      width={110}></Image>
      <Text>{res.data.title}</Text>
</View>
 

Почему это происходит?

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

1. Ты ничего не вернешь в map

2. О, как бы я это сделал? Извините, я новичок в родной реакции

Ответ №1:

В соответствии с комментарием , из которого вы ничего не возвращаете .map() , функция стрелки либо не должна иметь скобок «нравится (book) => axios.get( «, либо должна иметь скобки и использовать слово return «нравится (book) => { return axios.get( «.

return Оператор, на который вы смотрите вместе с <View> элементом, предназначен return для функции .then() обратного вызова, а не для всей .map() функции.

Но это не решит вашу проблему , потому что значение, которое вы будете возвращать из .map() , равно a Promise , а это не то, что вы можете распечатать в своем компоненте JSX.

@jamielarchin прав в том, что вы не можете выполнять выборку данных внутри своего render() метода. Это должно быть внутри метода жизненного componentDidMount цикла, такого как componentDidUpdate или внутри useEffect крючка. Поскольку вы только учитесь, я рекомендую вам учиться с использованием самого современного подхода, который заключается в использовании функционального компонента и useEffect .

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

Вы можете сделать этот Book компонент функциональным компонентом и сохранить текущий компонент «список книг» в качестве компонента класса.

 // the book id is the only prop
const Book = ({ id }) => {
  const [isError, setIsError] = useState(false);
  const [isLoading, setIsLoading] = useState(false);
  // save the book data here, once loaded
  const [data, setData] = useState();

  useEffect(
    () => {
      setIsLoading(true);
      axios
        .get('http://localhost:3000/books/id/'   id)
        .then((res) => setData(res.data))
        .catch((err) => setIsError(true))
        .finally(() => setIsLoading(false));
    },
    [id] // dependency on the book id
  );

  if (data !== undefined) {
    return (
      <View>
        <Image source={{ uri: data.cover }} height={150} width={110}></Image>
        <Text>{data.title}</Text>
        )}
      </View>
    );
  }
  // can show loading and error components too
  // but for now I'm just returning nothing
  return null;
};
 
 render() {
    return (
      <View style={{flex: 1, backgroundColor: 'white'}}>
        <ScrollView
          style={styles.scrollView}
          contentContainerStyle={{justifyContent: 'center'}}>
          <Text style={styles.heading}>Checked Out Books</Text>
          {this.state.books.map((book) => <Book id={book} key={book}/>)}
 

Ответ №2:

Извлечение данных должно выполняться методом жизненного цикла для компонентов класса. Вероятно, вы хотите использовать componentDidMount: https://reactjs.org/docs/react-component.html#componentdidmount

Ответ №3:

Вы не должны вызывать axios внутри рендеринга (это возможно с некоторыми корректировками, однако это не очень хорошая практика). Вы должны либо использовать крючки (например, useEffect), если вы находитесь в функциональном компоненте, либо использовать componentDidMount, если вы находитесь в компоненте класса (как я предполагаю). Примеры приведены ниже.

 class App extends React.Component {
  constructor(){
    this.state = {
        bookIds: [], //You would fill this beforehand
        books: [],
      }
  }

  componentDidMount(){
    for(let i = 0; i < bookIds; i  ){
      axios.get('http://localhost:3000/books/id/'   bookIds[i]).then((res) => {
         books.push(res); 
       }.catch((err) => {
           console.log(err);
           alert('Something went wrong.');
      });
    }
  }


  render() {
    return(
        <View style={{flex: 1, backgroundColor: 'white'}}>
        <ScrollView
          style={styles.scrollView}
          contentContainerStyle={{justifyContent: 'center'}}>
          <Text style={styles.heading}>Checked Out Books</Text>
          {this.state.books.map((book) => {
             return (
               <View>
                 <Image
                   source={{uri: book.data.cover}}
                   height={150}
                   width={110}>
                 </Image>
                 <Text>{book.data.title}</Text>
               </View>
            );
        })
      }
    );
  }
}
 

Я бы рекомендовал вам взглянуть на это: https://reactjs.org/docs/state-and-lifecycle.html.

Возможно, возникнут какие-то проблемы с скобками, Хорошего дня!