Вы имеете дело с асинхронными данными, вам нужно дождаться выполнения обещания, прежде чем оно сработает так, как вы ожидаете. Получение книг занимает некоторое время, поэтому есть задержка, пока книги не прибудут, и все, что у вас есть, - это обещание, что книги придут в конце концов.
Чтобы заставить это работать, вы можете попробовать:
useEffect(() => {
firebase.getBooks().then(books => setBooks(books))
}, []);
Когда функция завершается, выполняются следующие шаги:
Возвращаемое значение функции копируется в заполнитель, который был помещен в стек для этой цели.
Все после того, как указатель стекового кадра удален. Это уничтожает все локальные переменные и аргументы.
Возвращаемое значение выталкивается из стека и присваивается в качестве значения функции. Если значение функции никому не назначено, присвоение не происходит, и значение теряется.
Адрес следующей команды для выполнения извлекается из стека, и ЦПУ возобновляет выполнение с этой командой.
Когда вы возвращаете значение, создается копия. Область действия локальной переменной заканчивается, но копия создается и возвращается вызывающей функции. Пример:
int funcB() {
int j = 12;
return j;
}
void A() {
int i;
i = funcB();
}
Значение j (12) копируется и возвращается в i, так что я получу значение 12.
Это действительно зависит от того, какую переменную вы возвращаете. Если вы возвращаете примитив, то он возвращается копией, а не ссылкой, поэтому значение копируется в верхнюю часть стека (или, чаще всего, помещается в регистр), где вызывающая функция может его получить. Если вы выделяете объект или память в куче и возвращаете указатель, он не умирает, потому что он находится в куче, а не в стеке. Однако если вы разместите что-то в стеке и вернете это, это будет плохо. Например, любой из них будет очень плохим:
int *myBadAddingFunction(int a, int b)
{
int result;
result = a + b;
return &result; // this is very bad and the result is undefined
}
char *myOtherBadFunction()
{
char myString[256];
strcpy(myString, "This is my string!");
return myString; // also allocated on the stack, also bad
}
Просто для более подробного объяснения, ориентированного на модель памяти: когда вызывается функция, создается временное пространство для функции, в которую помещаются ее локальные переменные, называемые кадром . Когда функция (callee) возвращает свое значение, она помещает возвращаемое значение в фрейм функции, вызвавшей ее (callere), и затем фрейм callee уничтожается.
Часть «рамка уничтожена» - вот почему вы не можете возвращать указатели или ссылки на локальные переменные из функций. Указатель фактически является ячейкой памяти, поэтому возвращение ячейки памяти локальной переменной (по определению: переменная в кадре) становится некорректным после разрушения кадра. Поскольку фрейм вызываемого пользователя уничтожается, как только он возвращает свое значение, любой указатель или ссылка на локальную переменную сразу же неверны.
Локальная переменная копируется в возвращаемое значение. Конструкторы копирования вызываются для нетривиальных классов.
Если вы вернете указатель или ссылку на локальную переменную, у вас будут проблемы - как и подсказывает ваша интуиция.
Это зависит от типа возвращаемого товара. Если вы возвращаете по значению, создается новая копия переменной для возврата вызывающей стороне. В этом случае вам не нужно беспокоиться о времени жизни объекта, но вам, возможно, придется беспокоиться о стоимости копирования объектов (но, пожалуйста, не оптимизируйте преждевременно - правильность гораздо важнее):
std::string someFunc( std::string& const s)
{
return s + "copy";
}
Если функция возвращает ссылку, вам нужно быть осторожным с тем, что вы возвращаете, потому что срок ее службы должен превышать срок действия функции, и вызывающая сторона не обязательно сможет delete
ее использовать, если вы используете new
для создания объекта:
std::string& someFunc2( std::string const& s)
{
return s + "reference to a copy"; // this is bad - the temp object created will
// be destroyed after the expression the
// function call is in finishes.
// Some, but not all, compilers will warn
// about this.
}
Конечно, возвращаемые указатели будут иметь аналогичные соображения времени жизни.