草庐IT

UE4 C++:TArray容器

BBBourne 2023-04-11 原文

目录

概述

创建

添加元素

Init :填充多个相同值

Add:可添加重复元素,添加时会创建临时变量再复制

AddUnique:不可添加重复元素

Emplace:添加时不会创建临时变量,性能好于Add

Append: 可一次性添加其他TArray中的多个元素,或者指向常规C数组的指针及该数组的大小

Insert:在给定索引处添加单个元素或元素数组的副本

SetNum: 函数可直接设置数组元素的数量。

迭代

基于范围的for语句

常规for

迭代器

排序

Sort

HeapSort:堆排序(不稳定)

StableSort:排序后保证等值元素的相对排序。StableSort 作为归并排序实现

查询

GetData:函数返回指向数组中元素的指针,该操作直接访问数组内存

GetTypeSize:获取单个元素的大小

[]:索引运算符获取元素,返回的是一个引用,可用于操作元素

IsValidIndex:询问容器,特定索引是否有效(0≤index())<>

Last:从数组末端反向索引,默认为0

Top:返回最后一个元素,不接受索引

Contains:是否包含特定元素

ContainsByPredicate:是否包含与特定谓词匹配的元素

Find:元素是否存在并返回找到的首个元素索引

FindLast:元素是否存在并返回找到的最末元素索引

IndexOfByKey:返回首个匹配到的元素的索引;未找到返回INDEX_NONE

IndexOfByPredicate:查找与特定谓词匹配的首个元素的索引;

FindByKey:将元素和任意对象对比,并返回首个匹配到的元素的指针,如果未匹配到,则返回nullptr

FindByPredicate:和IndexOfByPredicate相似,不同的是,它的返回值是指针,而不是索引

FilterByPredicate:可获取与特定谓词匹配的元素数组

移除元素

Remove:移除数组中的元素

RemoveSingle:移除数组中首个匹配元素

RemoveAt:按照索引移除元素

RemoveAll:移除与谓词匹配的元素

RemovSwap、RemoveAtSwap、RemoveAllSwap

Empty:移除数组中所有元素

Reset:与 Empty类似,该函数将不释放内存

运算符

+=:可替代Append函数进行数组连接

MoveTemp:可将一个数组中的内容移动到另一个数组中,源数组将被清空

==、!=:可对数组进行比较

Heapify:可将现有数组转换为堆

HeapPush:新元素添加到堆,对其他节点进行重新排序,以对堆进行维护

HeapPop、HeadPopDiscard:移除堆顶结点

HeapRemoveAt:删除数组中给定索引处的元素,然后重新排列元素,对堆进行维护

HeapTop:查看堆的顶部节点,无需变更数组

Slack

GetSlack:找出数组中的Slack量,相当于Max()-Min() 

Max:获取到容器重新分配之前数组可保存的最大元素数量

Empty()

Reset():与Empty函数类似,不同之处是若当前内存分配已提供请求的Slack,该函数将不释放内存。但若请求的Slack较大,其将分配更多内存

Shrink():移除所有Slack

原始内存


概述

  • TArray是UE中最常用的容器类。速度快、内存消耗小、安全性高
  • 其设计时未考虑扩展问题,因此建议在实际操作中 不要使用 new 和 delete 创建和销毁TArray实例
  • TArray元素作为数值类型时,被销毁时其中的元素也将被销毁。若在另以TArray中创建TArray变量,其元素将复制到新变量中,且不会共享状态

创建

TArray<int32> IntArray;

添加元素

Init :填充多个相同值

IntArray.Init(10, 5); //==>[10,10,10,10,10]

Add:可添加重复元素,添加时会创建临时变量再复制

AddUnique:不可添加重复元素

Emplace:添加时不会创建临时变量,性能好于Add

TArray<FString> StrArr;
StrArr.Add(TEXT("Hello"));
IntArray.AddUnique(TEXT("Hello"));
StrArr.Emplace(TEXT("World")); //==>["Hello","World"]

Append: 可一次性添加其他TArray中的多个元素,或者指向常规C数组的指针及该数组的大小

FString Arr[] = { TEXT("of"), TEXT("Tomorrow") };
StrArr.Append(Arr, ARRAY_COUNT(Arr)); //==>["Hello","World","of","Tomorrow"]

新元素添加到数组时,数组的分配器将根据需要分配内存。当前数组大小超出时,默认分配器将添加足够的内存,用于存储多个新元素。Add 和 Emplace 函数的多数效果相同,细微区别在于:

  • Add(或 Push)将元素类型的实例复制(或移动)到数组中。

  • Emplace 使用给定参数构建元素类型的新实例。

因此在 TArray<FString> 中,Add 将用字符串文字创建临时 FString,然后将该临时 FString 的内容移至容器内的新 FString 中;而 Emplace 将用字符串文字直接新建 FString。最终结果相同,但 Emplace 可避免创建临时文件。对于 FString 等非浅显数值类型而言,临时文件通常有害无益。

总体而言,Emplace 优于 Add,因此其可避免在调用点创建无需临时变量,并将此类变量复制或移动到容器中。根据经验,可将 Add 用于浅显类型,将 Emplace 用于其他类型。Emplace 的效率始终高于 Add,但 Add 的可读性可能更好。

仅在尚不存在等值元素时,AddUnique 才会向容器添加新元素。使用以下元素类型的运算符检查等值性:运算符==:

StrArr.AddUnique(TEXT("!"));
// StrArr == ["Hello","World","of","Tomorrow","!"]

StrArr.AddUnique(TEXT("!"));
// StrArr is unchanged as "!" is already an element

Insert:在给定索引处添加单个元素或元素数组的副本

StrArr.Insert(TEXT("Brave"), 1); //==>["Hello","Brave","World","of","Tomorrow","!"]

SetNum: 函数可直接设置数组元素的数量。

  • 如新数量大于当前数量,则使用元素类型的默认构造函数新建元素
  • 如新数量小于当前数量,SetNum 将移除元素。
StrArr.SetNum(8); //==>["Hello","Brave","World","of","Tomorrow","!","",""]

StrArr.SetNum(6); //==>["Hello","Brave","World","of","Tomorrow","!"]

迭代

基于范围的for语句

FString JoinedStr;
for (auto& Str :StrArr)
{
	JoinedStr += Str;
	JoinedStr += TEXT(" ");
} // JoinedStr == "Hello Brave World of Tomorrow !"

常规for

for (int32 Index = 0; Index != StrArr.Num(); ++Index)
{
	JoinedStr += StrArr[Index];
	JoinedStr += TEXT(" ");
}

迭代器

函数 CreateIterator 和 CreateConstIterator 可分别用于元素的读写和只读访问

for (auto It = StrArr.CreateConstIterator(); It; ++It)
{
	JoinedStr += *It;
	JoinedStr += TEXT(" ");
}

 

排序

Sort

StrArr.Sort(); //==>["!","Brave","Hello","of","Tomorrow","World"]

二进制谓词提供不同排序规则(lambda)

StrArr.Sort([](const FString& A, const FString& B){
		return A.len() < B.len();
	}); //按字符串长度排序, ==>["!","of","Hello","Brave","World","Tomorrow"]

HeapSort:堆排序(不稳定)

无论带或不带二元谓词,均可用于执行对排序。是否选择使用它则取决于特定数据和与 Sort 函数之间的排序效率对比。和 Sort 一样,HeapSort 并不稳定

StrArr.HeapSort([](const FString& A, const FString& B) {
	return A.Len() < B.Len();
}); //==>["!","of","Hello","Brave","World","Tomorrow"]

StableSort:排序后保证等值元素的相对排序。StableSort 作为归并排序实现

StrArr.StableSort([](const FString& A, const FString& B) {
	return A.Len() < B.Len();
}); //==>["!","of","Brave","Hello","World","Tomorrow"]

查询

Num:查询元素数量

int32 Count = StrArr.Num();  // Count == 6

GetData:函数返回指向数组中元素的指针,该操作直接访问数组内存

仅在数组存在且未执行更改数组的操作时,此指针方有效。仅 StrPtr 的首个 Num 指数才可被解除引用

FString* StrPtr = StrArr.GetData();
// StrPtr[0] == "!"
// StrPtr[1] == "of"
// ...
// StrPtr[5] == "Tomorrow"
// StrPtr[6] - undefined behavior

GetTypeSize:获取单个元素的大小

uint32 ElementSize = StrArr.GetTypeSize(); // ElementSize == sizeof(FString)

[]:索引运算符获取元素,返回的是一个引用,可用于操作元素

FString Elem1 = StrArr[1]; // Elem1 == "of"

StrArr[3] = StrArr[3].ToUpper(); //==>["!","of","Brave","HELLO","World","Tomorrow"]

IsValidIndex:询问容器,特定索引是否有效(0≤index<Num())

bool bValidM1 = StrArr.IsValidIndex(-1);// bValidM1 == false
bool bValid0  = StrArr.IsValidIndex(0); // bValid0  == true
bool bValid5  = StrArr.IsValidIndex(5); // bValid5  == true
bool bValid6  = StrArr.IsValidIndex(6); // bValid6  == false

Last:从数组末端反向索引,默认为0

Top:返回最后一个元素,不接受索引

FString ElemEnd  = StrArr.Last();  // ElemEnd  == "Tomorrow"
FString ElemEnd0 = StrArr.Last(0); // ElemEnd0 == "Tomorrow"
FString ElemEnd1 = StrArr.Last(1); // ElemEnd1 == "World"
FString ElemTop  = StrArr.Top();   // ElemTop  == "Tomorrow"

Contains:是否包含特定元素

bool bHello   = StrArr.Contains(TEXT("Hello"));   // bHello   == true
bool bGoodbye = StrArr.Contains(TEXT("Goodbye")); // bGoodbye == false

ContainsByPredicate:是否包含与特定谓词匹配的元素

bool bLen5 = StrArr.ContainsByPredicate([](const FString& Str){
	return Str.Len() == 5;
}); // bLen5 == true

bool bLen6 = StrArr.ContainsByPredicate([](const FString& Str){
	return Str.Len() == 6;
}); // bLen6 == false

Find:元素是否存在并返回找到的首个元素索引

int32 Index;
if (StrArr.Find(TEXT("Hello"), Index)){  
	// Index == 3
}  

int32 Index2 = StrArr.Find(TEXT("Hello"));    // Index2 == 3
int32 IndexNone  = StrArr.Find(TEXT("None")); // IndexNone == INDEX_NONE(实质上是-1)

FindLast:元素是否存在并返回找到的最末元素索引

int32 IndexLast;
if (StrArr.FindLast(TEXT("Hello"), IndexLast)){
	// IndexLast == 3, because there aren't any duplicates
}

int32 IndexLast2 = StrArr.FindLast(TEXT("Hello")); // IndexLast2 == 3

IndexOfByKey:返回首个匹配到的元素的索引;未找到返回INDEX_NONE

IndexOfByPredicate:查找与特定谓词匹配的首个元素的索引;

int32 Index = StrArr.IndexOfByPredicate([](const FString& Str){
	return Str.Contains(TEXT("r"));
}); // Index == 2

FindByKey:将元素和任意对象对比,并返回首个匹配到的元素的指针,如果未匹配到,则返回nullptr

auto* OfPtr  = StrArr.FindByKey(TEXT("of"))); // OfPtr  == &StrArr[1]
auto* ThePtr = StrArr.FindByKey(TEXT("the"))); // ThePtr == nullptr

FindByPredicate:和IndexOfByPredicate相似,不同的是,它的返回值是指针,而不是索引

auto* Len5Ptr = StrArr.FindByPredicate([](const FString& Str){
	return Str.Len() == 5;
}); // Len5Ptr == &StrArr[2]

auto* Len6Ptr = StrArr.FindByPredicate([](const FString& Str){
	return Str.Len() == 6;
}); // Len6Ptr == nullptr

FilterByPredicate:可获取与特定谓词匹配的元素数组

auto Filter = StrArray.FilterByPredicate([](const FString& Str){
	return !Str.IsEmpty() && Str[0] < TEXT('M');
});

移除元素

Remove:移除数组中的元素

TArray<int32> ValArr;
int32 Temp[] = { 10, 20, 30, 5, 10, 15, 20, 25, 30 };
ValArr.Append(Temp, ARRAY_COUNT(Temp)); //==>[10,20,30,5,10,15,20,25,30]

ValArr.Remove(20); //==>[10,30,5,10,15,25,30]

RemoveSingle:移除数组中首个匹配元素

ValArr.RemoveSingle(30); //==>[10,5,10,15,25,30]

RemoveAt:按照索引移除元素

ValArr.RemoveAt(2); // 移除下标为2的元素, ==>[10,5,15,25,30]
ValArr.RemoveAt(99); // 引发错误,越界

RemoveAll:移除与谓词匹配的元素

ValArr.RemoveAll([](int32 Val) {
	return Val % 3 == 0; }); //移除为3倍数的所有数值, ==> [10,5,25]

RemovSwap、RemoveAtSwap、RemoveAllSwap

移动过程存在开销。如不需要剩余元素排序,可使用 RemoveSwap、RemoveAtSwap 和 RemoveAllSwap 函数减少此开销。此类函数的工作方式与其非交换变种相似,不同之处在于其不保证剩余元素的排序,因此可更快地完成任务:

TArray<int32> ValArr2;
for (int32 i = 0; i != 10; ++i)
	ValArr2.Add(i % 5); //==>[0,1,2,3,4,0,1,2,3,4]

ValArr2.RemoveSwap(2); //==>[0,1,4,3,4,0,1,3]

ValArr2.RemoveAtSwap(1); //==>[0,3,4,3,4,0,1]

ValArr2.RemoveAllSwap([](int32 Val) {
	return Val % 3 == 0; }); //==>[1,4,4]

Empty:移除数组中所有元素

ValArr2.Empty(); //==>[]

Reset:与 Empty类似,该函数将不释放内存

ValArr2.Reset (); //==>[]

运算符

数组是常规数值类型,可使用标准复制构造函数或赋值运算符进行复制。由于数组严格拥有其元素,复制数组的操作是深层的,因此新数组将拥有其自身的元素副本

TArray<int32> ValArr3;
ValArr3.Add(1);
ValArr3.Add(2);
ValArr3.Add(3);

auto ValArr4 = ValArr3; // ValArr4 == [1,2,3];
ValArr4[0] = 5;         // ValArr4 == [5,2,3]; ValArr3 == [1,2,3];

+=:可替代Append函数进行数组连接

ValArr4 += ValArr3; //==>[5,2,3,1,2,3]

MoveTemp:可将一个数组中的内容移动到另一个数组中,源数组将被清空

ValArr3 = MoveTemp(ValArr4);  // ValArr3 == [5,2,3,1,2,3]; ValArr4 == []

==、!=:可对数组进行比较

元素的排序很重要:只有元素的顺序和数量相同时,两个数组才被视为相同

TArray<FString> FlavorArr1;
FlavorArr1.Emplace(TEXT("Chocolate"));
FlavorArr1.Emplace(TEXT("Vanilla")); // FlavorArr1 == ["Chocolate","Vanilla"]

auto FlavorArr2 = FlavorArr1;        // FlavorArr2 == ["Chocolate","Vanilla"]

bool bComparison1 = FlavorArr1 == FlavorArr2;  // bComparison1 == true

for ( auto& Str : FlavorArr2 )
{
	Str = Str.ToUpper();
} // FlavorArr2 == ["CHOCOLATE","VANILLA"]

bool bComparison2 = FlavorArr1 == FlavorArr2; // bComparison2 == true,因为FString的对比忽略大小写

Exchange(FlavorArr2[0], FlavorArr2[1]); // FlavorArr2 == ["VANILLA","CHOCOLATE"]

bool bComparison3 = FlavorArr1 == FlavorArr2; // bComparison3 == false,因为两个数组内的元素顺序不同

TArray 拥有支持二叉堆数据结构的函数。堆是一种二叉树,其中父节点的排序等于或高于其子节点。作为数组实现时,树的根节点位于元素0,索引N处节点的左右子节点的指数分别为2N+1和2N+2。子节点彼此间不存在特定排序。

Heapify:可将现有数组转换为堆

TArray<int32> HeapArr;
for (int32 Val = 10; Val != 0; --Val){
	HeapArr.Add(Val);
} // HeapArr == [10,9,8,7,6,5,4,3,2,1]

HeapArr.Heapify(); // HeapArr == [1,2,4,3,6,5,8,10,7,9]

HeapPush:新元素添加到堆,对其他节点进行重新排序,以对堆进行维护

HeapArr.HeapPush(4); // HeapArr == [1,2,4,3,4,5,8,10,7,9,6]

HeapPop、HeadPopDiscard:移除堆顶结点

这两个函数的区别在于前者引用元素的类型来返回顶部元素的副本,而后者只是简单地移除顶部节点,不进行任何形式的返回。两个函数得出的数组变更一致,重新正确排序其他元素可对堆进行维护

int32 TopNode;
HeapArr.HeapPop(TopNode); // TopNode == 1; HeapArr == [2,3,4,6,4,5,8,10,7,9]

HeapRemoveAt:删除数组中给定索引处的元素,然后重新排列元素,对堆进行维护

HeapArr.HeapRemoveAt(1); // HeapArr == [2,4,4,6,9,5,8,10,7]

HeapTop:查看堆的顶部节点,无需变更数组

int32 Top = HeapArr.HeapTop();  // Top == 2

Slack

因为数组的尺寸可进行调整,因此它们使用的是可变内存量。为避免每次添加元素时需要重新分配,分配器通常会提供比需求更多的内存,使之后进行的Add调用不会因为重新分配而出现性能损失。同样,删除元素通常不会释放内存。

  • 容器中现有元素数量和下次分配之前可添加的元素数量之差为Slack
  • 默认构建的数组不分配内存,slack初始为0

GetSlack:找出数组中的Slack量,相当于Max()-Min() 

Max:获取到容器重新分配之前数组可保存的最大元素数量

  • 分配器确定重新分配后的容器中的Slack量,因此Slack不是常量
TArray<int32> SlackArray;
// SlackArray.GetSlack() == 0
// SlackArray.Num()      == 0
// SlackArray.Max()      == 0

SlackArray.Add(1);
// SlackArray.GetSlack() == 3
// SlackArray.Num()      == 1
// SlackArray.Max()      == 4

SlackArray.Add(2);
SlackArray.Add(3);
SlackArray.Add(4);
SlackArray.Add(5);
// SlackArray.GetSlack() == 17
// SlackArray.Num()      == 5
// SlackArray.Max()      == 22
  • 虽然无需管理Slack,但可管理Slack对数组优化,以满足需求

Empty()

例如,如需要向数组添加大约100个新元素,则可在添加前确保拥有可至少存储100个新元素的Slack,以便添加新元素时无需分配内存。上文所述的 Empty 函数接受可选Slack参数

SlackArray.Empty();
// SlackArray.GetSlack() == 0
// SlackArray.Num()      == 0
// SlackArray.Max()      == 0
SlackArray.Empty(3);
// SlackArray.GetSlack() == 3
// SlackArray.Num()      == 0
// SlackArray.Max()      == 3
SlackArray.Add(1);
SlackArray.Add(2);
SlackArray.Add(3);
// SlackArray.GetSlack() == 0
// SlackArray.Num()      == 3
// SlackArray.Max()      == 3

Reset():与Empty函数类似,不同之处是若当前内存分配已提供请求的Slack,该函数将不释放内存。但若请求的Slack较大,其将分配更多内存

SlackArray.Reset(0);
// SlackArray.GetSlack() == 3
// SlackArray.Num()      == 0
// SlackArray.Max()      == 3
SlackArray.Reset(10);
// SlackArray.GetSlack() == 10
// SlackArray.Num()      == 0
// SlackArray.Max()      == 10

Shrink():移除所有Slack

此函数将把分配重新调整为所需要的大小,使其保存当前的元素序列,而无需实际移动元素

SlackArray.Add(5);
SlackArray.Add(10);
SlackArray.Add(15);
SlackArray.Add(20);
// SlackArray.GetSlack() == 6
// SlackArray.Num()      == 4
// SlackArray.Max()      == 10
SlackArray.Shrink();
// SlackArray.GetSlack() == 0
// SlackArray.Num()      == 4
// SlackArray.Max()      == 4

原始内存

参考链接:

 【UE4 C++ 基础知识】<5> 容器——TArray - 砥才人 - 博客园 (cnblogs.com)

Array Containers in Unreal Engine | 虚幻引擎5.0文档

有关UE4 C++:TArray容器的更多相关文章

  1. UE4 源码阅读:从引擎启动到Receive Begin Play - 2

    一、引擎主循环UE版本:4.27一、引擎主循环的位置:Launch.cpp:GuardedMain函数二、、GuardedMain函数执行逻辑:1、EnginePreInit:加载大多数模块int32ErrorLevel=EnginePreInit(CmdLine);PreInit模块加载顺序:模块加载过程:(1)注册模块中定义的UObject,同时为每个类构造一个类默认对象(CDO,记录类的默认状态,作为模板用于子类实例创建)(2)调用模块的StartUpModule方法2、FEngineLoop::Init()1、检查Engine的配置文件找出使用了哪一个GameEngine类(UGame

  2. 在保持文本不透明度的同时,可以使用仅使用HTML制作一个透明的容器? - 2

    我想在保持文本/图像不透明的同时使我的容器背景透明。只能使用HTML做到这一点吗?这是我的代码:看答案我看到了您的问题,如果我正确理解您,我想我知道您可以做什么。我注意到的一件事是,在我进一步走之前,看起来您正在使用引导程序代码。如果您更改了可能与此相关的CSS样式表,则可能会更好,更有效,也可能不会破坏整体代码的其他元素,但是让我们看看我的解决方案是否对您有效。基本上您想做的是:1)在您的HTML中编写一个“样式”标签,然后在其中放入样式(CSS)属性(您可以将其放入HTML代码的标题中以更好地跟踪它)。2)使用提供背景颜色的“RGBA”格式,并将其不透明度为“0”作为代码段的第四值。因此,

  3. ruby-on-rails - 使用 AWS Elastic Beanstalk 和 Ruby 容器设置私有(private) Github 访问 - 2

    经过recenttutorial关于使用Git为Ruby部署设置AWSElasticBeanstalk,我只是从我的CI服务器设置了一个ElasticBeanstalk环境。但是,应用程序无法启动。我查看日志发现bundleinstall失败并显示一条错误消息。Fetchinggit@github.com:example/private-repository.gitHostkeyverificationfailed.fatal:Theremoteendhungupunexpectedly[31mGiterror:commandgitclone'git@github.com:exampl

  4. vue2+element-ui,el-aside侧边栏容器收缩与展开 - 2

    一、概览实现效果如下:二、项目环境1、nodejs版本node-vv16.16.02、npm版本npm-vnpmWARNconfigglobal`--global`,`--local`aredeprecated.Use`--location=global`instead.8.15.03、vue脚手架版本vue-V@vue/cli5.0.8三、创建vue项目1、创建名为vuetest的项目vuecreatevuetest选择Default([Vue2]babel,eslint)  2、切换到项目目录,启动项目cdvuetestnpmrunserve 3、使用浏览器预览 http://localh

  5. ruby - Ruby 有像栈、队列、链表、映射或集合这样的容器吗? - 2

    我在网上查了几个Ruby教程,他们似乎什么都用数组。那么如何在Ruby中实现以下数据结构呢?堆栈队列链表map组 最佳答案 (从评论中移出)好吧,通过限制堆栈或队列方法(push、pop、shift、unshift),数组可以是堆栈或队列。使用push/pop提供LIFO(后进先出)行为(堆栈),而使用push/shift或unshift/pop提供FIFO行为(队列)。map是hashes,和一个Set类已经存在。您可以使用类实现链表,但数组将使用标准数组方法提供类似于链表的行为。 关

  6. javascript - 选择容器中的最后一个词 - 2

    我只是想知道是否有办法选择DIV中的最后一个WORD。我认为没有任何明显的方法可以做到这一点,那么有什么变通办法吗?我不介意使用CSS或Javascript来实现这一点。提前致谢 最佳答案 或者没有,它归结为基本的字符串操作(使用match())方法。varwords=$('#your_div').text().match(/(\w+)/g);if(words.length){varlast_word=words[words.length-1];}我们使用match()构建所有单词的数组方法,然后获取最后一个(varlast_wor

  7. javascript - 使用 Knockout 组件时替换容器元素 - 2

    有没有办法配置Knockoutcomponent替换容器元素而不是将其内容嵌套在容器元素中?例如,如果我使用以下模板将自定义组件注册为my-custom-element:Helloworld!是否可以像这样使用组件:最终产品是这样的:Helloworld!而不是这样:(Knockout默认渲染组件的方式)Helloworld!Basedontheanswertothisquestion,似乎此功能内置于模板引擎中,我假设在呈现组件模板时也会使用它。有没有一种方法可以指定组件应该使用replaceNode的renderMode进行渲染?我知道“虚拟元素”语法,它允许在HTML注释中定义组

  8. javascript - ReactJS - ReactMount : Root element has been removed from its original container. 新容器 - 2

    这个错误是什么意思?如何解决?ReactMount:Rootelementhasbeenremovedfromitsoriginalcontainer.Newcontainer在这之后我得到了这个:Uncaughtobjectreact.js:15915invariantreact.js:15915ReactMount.findComponentRootreact.js:10584ReactMount.findReactNodeByIDreact.js:10480getNodereact.js:10089(anonymousfunction)react.js:7307(anonymou

  9. javascript - 在 docker 容器中安装 yarn 说缺少依赖 - 2

    我正在使用node:6.7.0图像作为我的docker容器,然后按照yarn的安装指南进行操作sudoapt-keyadv--keyserverpgp.mit.edu--recvD101F7899D41F3C3echo"debhttp://dl.yarnpkg.com/debian/stablemain"|sudotee/etc/apt/sources.list.d/yarn.list然后我做apt-getupdate&&apt-getinstallyarn但此时我收到一条错误消息,上面写着yarn:Depends:nodejs(>=4.0.0)butitisnotgoingtobei

  10. javascript - 如何将输入字段数据从模态传递到 react-Native 中的容器? - 2

    这是我正在使用的:{}}>在容器中我不知道如何将数据从模态传递到父组件。任何类型的教程或链接都可以。提前致谢。 最佳答案 让我们假设您的模态框在/components/MyModal中单独归档以概括事物。您可以让您的Modal调用一个函数,在每次输入文本更改时通过props传递该函数。这是您可以使用的简单回调逻辑。尽可能避免使用refs。importMyModalfrom'../components/MyModal';...classHomeextendsComponent{onInputChanged=(changedText)=

随机推荐