当前位置:   article > 正文

arkts鸿蒙@State定义复杂嵌套数据结构子级更新后视图不更新_arkts开发数组对象值改变,视图不更新

arkts开发数组对象值改变,视图不更新
数据结构如下:评论列表中带有的每条评论嵌套回复列表
  1. // 评论字段
  2. export interface CommentInterface {
  3. id:number,//主键
  4. content:string,//评论内容
  5. parentId:number,//父节点id
  6. type:string,// 类型
  7. topId:number,//顶级节点id
  8. relationId:number,//影片id
  9. createTime:string,//创建时间
  10. updateTime:string,//更新时间
  11. replyCount:number,//回复数量
  12. userId:string,//用户id
  13. username:string,//用户名
  14. avater:string,//用户头像
  15. replyUserId:string,//被回复者id
  16. replyUserName:string,//被回复者名称
  17. showCommentCount:string,//显示的回复数量
  18. replyPageNum:number,// 回复数量
  19. replyList:Array<CommentInterface>// 回复列表
  20. }

后端接口返回格式如下:

  1. [
  2. {
  3. "id": 112,
  4. "content": "精彩",
  5. "parentId": null,
  6. "topId": null,
  7. "relationId": 72667,
  8. "type": "MOVIE",
  9. "createTime": "2024-05-25T07:17:28.000+0000",
  10. "updateTime": null,
  11. "replyCount": 1,
  12. "userId": "灯火阑珊",
  13. "username": "灯火阑珊2",
  14. "avater": "/static/user/avater/灯火阑珊.jpg",
  15. "replyUserId": null,
  16. "replyUserName": null,
  17. "replyList": [
  18. {
  19. "id": 148,
  20. "content": "666",
  21. "parentId": 112,
  22. "topId": 112,
  23. "relationId": 72667,
  24. "type": "MOVIE",
  25. "createTime": "2024-05-26T08:07:53.000+0000",
  26. "updateTime": null,
  27. "replyCount": 0,
  28. "userId": "初晓微芒",
  29. "username": "初晓微芒",
  30. "avater": "/static/user/avater/初晓微芒.jpg",
  31. "replyUserId": "灯火阑珊",
  32. "replyUserName": "灯火阑珊2",
  33. "replyList": null
  34. }
  35. ]
  36. }
  37. ]

展示效果如下

点击回复,向item.replyList中插入一条回复内容,视图不更新,但数据库已经插入成功

  1. // 发送评论
  2. insertCommentService(commentItem).then((res) => {
  3. if (this.firstComment) { // 二级评论,相当于回复,插入一条回复
  4. this.commentList[this.replyIndex].replyList.push(res.data);
  5. } else { // 一级评论
  6. this.commentList.push(res.data);
  7. }
  8. this.dialogController?.close();
  9. this.replyComment = this.firstComment = null;
  10. this.text = '';
  11. this.focusableInput = false;
  12. }).finally(() => {
  13. this.loading = false;
  14. });

数据库中显示插入数据成功了,但是视图没有更新

解决办法1(推荐第2种方法):

1、把原来的数组解构重新赋值,

2、往新定义的数组里面添加回复数据

3、重新赋值给原来的数据,即可实现视图更新,

原理:强制改变原数组的内存地址,让视图重新渲染

  1. // 发送评论
  2. insertCommentService(commentItem).then((res) => {
  3. // 必须重新解构,然后再赋值,否则添加回复不生效
  4. const commentList = [...this.commentList];
  5. if (this.firstComment) { // 二级评论,相当于回复
  6. commentList[this.replyIndex].replyList.push(res.data);
  7. } else { // 一级评论
  8. commentList.push(res.data);
  9. }
  10. // 重新赋值,改变对象的内存地址,否则添加回复不生效
  11. this.commentList = commentList;
  12. this.dialogController?.close();
  13. this.replyComment = this.firstComment = null;
  14. this.text = '';
  15. this.focusableInput = false;
  16. }).finally(() => {
  17. this.loading = false;
  18. });

解决方法2(推荐):

1、把要添加回复的那一条数据解构重新赋值给新的一个对象

2、往新定义的对象里面的列表添加回复数据

3、使用数组splice方法,把原来数组里面的一条数据替换成新定义的对象,

原理:只改变数据中一条数据的内存地址,不改变原来数组的内容地址,性能要高于第一种方案

  1. // 发送评论
  2. insertCommentService(commentItem).then((res) => {
  3. if (this.firstComment) { // 二级评论,相当于回复
  4. // 必须重新解构,然后再赋值,否则添加回复不生效
  5. const commentItem = {...this.commentList[this.replyIndex]};
  6. commentItem.replyList === null && (commentItem.replyList = []);
  7. commentItem.replyList.push(res.data);// 添加回复列表
  8. this.commentList.splice(this.replyIndex,1,commentItem);// 替换掉原数据里面的那一条数据
  9. } else { // 一级评论
  10. this.commentList.push(res.data);
  11. }
  12. // 重新赋值,改变对象的内存地址,否则添加回复不生效
  13. this.dialogController?.close();
  14. this.replyComment = this.firstComment = null;
  15. this.text = '';
  16. this.focusableInput = false;
  17. }).finally(() => {
  18. this.loading = false;
  19. });

完整代码如下

  1. import * as colors from '../../theme/color';
  2. import * as size from '../../theme/size';
  3. import {getTopCommentListService,insertCommentService} from '../service/Index';
  4. import { HOST } from '../../config/constant';
  5. import { CommentInterface } from '../../music/interface/Index';
  6. import { formatTime } from '../../utils/common';
  7. // 传入buildCommentList方法必须是一个对象形式,否则无法实现响应式
  8. interface CommentParamsInterface{
  9. commentList:Array<CommentInterface>
  10. }
  11. @Component
  12. export default struct CommentComponent{
  13. @Prop relationId:number;
  14. @Prop commentListStr:string;// 评论数组字符串
  15. @Prop type:string;
  16. @State commentTotal:number = 0;
  17. @State commentList:Array<CommentInterface> = [];
  18. @State text:string = '';// 评论框文字
  19. @State firstComment:CommentInterface = null;
  20. @State replyComment:CommentInterface = null;
  21. @State replyIndex:number = -1;
  22. @State focusableInput:boolean = false;
  23. private loading:boolean = false;
  24. private scroller: Scroller = new Scroller()
  25. private dialogController:CustomDialogController;
  26. aboutToAppear(){
  27. /**
  28. * @author: wuwenqiang
  29. * @description: 获取评论列表
  30. * @date: 2024-05-25 21:36
  31. */
  32. if(this.commentListStr){
  33. this.commentList = JSON.parse(this.commentListStr) as Array<CommentInterface>;
  34. }else{
  35. getTopCommentListService(this.relationId,this.type,1,20).then(res => {
  36. this.commentList = res.data;
  37. this.commentTotal = res.total;
  38. });
  39. }
  40. }
  41. /**
  42. * @author: wuwenqiang
  43. * @description: 打开评论框弹窗
  44. * @date: 2024-05-26 14:26
  45. */
  46. openDialog():void{
  47. if(!this.dialogController){
  48. this.dialogController = new CustomDialogController({
  49. customStyle: true,
  50. builder: this.buildCommentInput(),
  51. alignment: DialogAlignment.Bottom,
  52. })
  53. }
  54. this.dialogController.open()
  55. }
  56. /**
  57. * @author: wuwenqiang
  58. * @description: 创建评论框
  59. * @date: 2024-05-26 14:26
  60. */
  61. @Builder buildCommentInput(){
  62. Column() {
  63. Row() {
  64. TextInput({ text:this.text,placeholder: this.replyComment ? `回复${this.replyComment.username}` : (this.firstComment ? `回复${this.firstComment.username}` : '评论') })
  65. .layoutWeight(1)
  66. .focusable(this.focusableInput)
  67. .height(size.inputHeight)
  68. .onChange((value) => {
  69. this.text = value;
  70. }).onClick(() => {
  71. this.focusableInput = true
  72. })
  73. Button('发送', { type: ButtonType.Capsule, stateEffect: true })
  74. .backgroundColor(colors.lineBackgroundColor)
  75. .width(size.btnWidth)
  76. .enabled(Boolean(this.text))
  77. .height(size.inputHeight)
  78. .margin({ left: size.pagePadding })
  79. .onClick(() => {
  80. if (this.loading) return;
  81. this.loading = true;
  82. const commentItem: CommentInterface = {
  83. id: 0, //主键
  84. content: this.text, //评论内容
  85. parentId: this.replyComment?.id, //父节点id
  86. topId: this.firstComment?.id, //顶级节点id
  87. type: this.type, // 类型
  88. relationId: this.relationId, //影片id
  89. createTime: "", //创建时间
  90. updateTime: "", //更新时间
  91. replyCount: 0, //回复数量
  92. userId: "", //用户id
  93. username: "", //用户名
  94. avater: "", //用户头像
  95. replyUserId: "", //被回复者id
  96. replyUserName: "", //被回复者名称
  97. showCommentCount: "", //显示的回复数量
  98. replyPageNum: 0,
  99. replyList: []
  100. }
  101. // 发送评论
  102. insertCommentService(commentItem).then((res) => {
  103. if (this.firstComment) { // 二级评论,相当于回复
  104. // 必须重新解构,然后再赋值,否则添加回复不生效
  105. const commentItem = {...this.commentList[this.replyIndex]};
  106. commentItem.replyList === null && (commentItem.replyList = []);
  107. commentItem.replyList.push(res.data);// 添加回复列表
  108. this.commentList.splice(this.replyIndex,1,commentItem);// 替换掉原数据里面的那一条数据
  109. } else { // 一级评论
  110. this.commentList.push(res.data);
  111. }
  112. // 重新赋值,改变对象的内存地址,否则添加回复不生效
  113. this.dialogController?.close();
  114. this.replyComment = this.firstComment = null;
  115. this.text = '';
  116. this.focusableInput = false;
  117. }).finally(() => {
  118. this.loading = false;
  119. });
  120. })
  121. }.backgroundColor(colors.blockColor).padding(size.pagePadding)
  122. }
  123. .width('100%')
  124. }
  125. /**
  126. * @author: wuwenqiang
  127. * @description: 点击弹出评论框
  128. * @date: 2024-05-26 14:26
  129. */
  130. useReply(item:CommentInterface,index:number){
  131. if(this.commentListStr){
  132. this.openDialog();
  133. }
  134. this.focusableInput = true;
  135. this.replyIndex = index;
  136. if(item.topId){
  137. this.replyComment = item;// 二级评论,即回复的内容
  138. this.firstComment = this.commentList.find(aItem => aItem.id === item.topId)
  139. }else{
  140. this.replyComment = this.firstComment = item;// 点击的是一级评论
  141. }
  142. }
  143. /**
  144. * @author: wuwenqiang
  145. * @description: 创建评论列表,参数必须用对象或者接口形式传递,否则参数变化了,视图不更新
  146. * @date: 2024-05-25 16:30
  147. */
  148. @Builder buildCommentList(commentParams:CommentParamsInterface){
  149. Column({space:size.pagePadding}){
  150. ForEach(commentParams.commentList,(aItem:CommentInterface,aIndex:number) => {
  151. Row(){
  152. Image(aItem.avater ? HOST + aItem.avater : $r('app.media.default_avater'))
  153. .width(aItem.topId ? size.smallAvaterSize :size.middleAvaterSize)
  154. .height(aItem.topId ? size.smallAvaterSize :size.middleAvaterSize)
  155. .borderRadius(aItem.topId ? size.smallAvaterSize :size.middleAvaterSize)
  156. Column(){
  157. Text(aItem.topId ? `${aItem.username}${aItem.replyUserName}` :aItem.username)
  158. .fontColor(colors.disableTextColor).margin({bottom:size.miniPadding})
  159. Text(aItem.content).margin({bottom:size.miniPadding})
  160. Text(formatTime(aItem.createTime)).fontColor(colors.disableTextColor)
  161. if(aItem.replyList?.length > 0){
  162. Blank().height(size.pagePadding)
  163. // 参数必须用对象或者接口形式传递,否则参数变化了,视图不更新
  164. this.buildCommentList({commentList:aItem.replyList})
  165. }
  166. }.layoutWeight(1)
  167. .alignItems(HorizontalAlign.Start)
  168. .margin({left:size.pagePadding})
  169. .onClick(this.useReply.bind(this,aItem,aIndex))
  170. }
  171. .justifyContent(FlexAlign.Start)
  172. .alignItems(VerticalAlign.Top)
  173. .width('100%')
  174. })
  175. }
  176. }
  177. build(){
  178. Column(){
  179. Text(`${this.commentTotal}条评论`)
  180. .padding(size.pagePadding)
  181. .textAlign(TextAlign.Center)
  182. .border({
  183. width: { bottom: 1 },
  184. color: { bottom: colors.borderColor },
  185. style: { bottom: BorderStyle.Solid }
  186. }).width('100%')
  187. Scroll(this.scroller) {
  188. if(this.commentList.length > 0) {
  189. // 必须用对象的方式传递,否则this.commentList发生变化之后,视图不会更新
  190. this.buildCommentList({commentList:this.commentList})
  191. }else{
  192. Text('暂无评论')
  193. .width('100%')
  194. .height('100%')
  195. .textAlign(TextAlign.Center)
  196. .alignSelf(ItemAlign.Center)
  197. }
  198. }
  199. .scrollable(ScrollDirection.Vertical)
  200. .layoutWeight(1)
  201. .align(Alignment.Top)
  202. .padding(size.pagePadding)
  203. if(!this.commentListStr){
  204. Divider().height(1).color(colors.borderColor)
  205. this.buildCommentInput()
  206. }
  207. }.width('100%').height('100%')
  208. }
  209. }

实现效果如下:

github地址:https://github.com/wuyuanwuhui99/Harmony-arkts-movie-music-app-ui

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/繁依Fanyi0/article/detail/789998
推荐阅读
相关标签
  

闽ICP备14008679号