通过引用更新树结构中的项目并返回更新后的树结构

2024-02-13

我目前正在使用 HyperappJS (V2) 和 RamdaJS 学习函数式编程。我的第一个项目是一个简单的博客应用程序,用户可以在其中对帖子或其他评论进行评论。评论以树形结构表示。

我的状态看起来像这样:

// state.js
export default {
    posts: [
        {
            topic: `Topic A`, 
            comments: []
        },
        {
            topic: `Topic B`, 
            comments: [
                {
                    text: `Comment`, 
                    comments: [ /* ... */ ]
                }
            ]
        },
        {
            topic: `Topic C`, 
            comments: []
        }
    ],
    otherstuff: ...
}

当用户想要添加评论时,我将当前树项传递给我的 addComment 操作。在那里,我将注释添加到引用的项目中,并返回一个新的状态对象以触发视图更新。

所以,目前我正在这样做并且工作正常:

// actions.js
import {concat} from 'ramda'   
export default {
    addComment: (state, args) => {
        args.item.comments = concat(
            args.item.comments, 
            [{text: args.text, comments: []}]
        )
        return {...state}
    }
}

我的问题:这种方法正确吗?有什么方法可以清理这段代码并使其更实用吗?我正在寻找的是这样的:

addComment: (state, args) => ({
    ...state,
    posts: addCommentToReferencedPostItemAndReturnUpdatedPosts(args, state.posts)
})

Ramda 有意设计为不修改用户数据。通过引用传递某些内容没有帮助; Ramda 仍然拒绝改变它。

另一种选择是看看您是否可以通过path到要添加注释的节点。 Ramda 可以使用path with lensPath https://ramdajs.com/docs/#lensPath and over https://ramdajs.com/docs/#over制作一个将返回新的版本state对象,像这样:

const addComment = (state, {text, path}) => 
  over (
    lensPath (['posts', ...intersperse ('comments', path), 'comments']), 
    append ({text, comments: []}), 
    state
  )

const state = {
  posts: [
    {topic: `Topic A`, comments: []},
    {topic: `Topic B`, comments: [{text: `Comment`, comments: [
      {text: 'foo', comments: []}
      // path [1, 0] will add here
    ]}]},
    {topic: `Topic C`, comments: []}
  ],
  otherstuff: {}
}

console .log (
  addComment (state, {path: [1, 0], text: 'bar'})
)
//=> {
//   posts: [
//     {topic: `Topic A`, comments: []},
//     {topic: `Topic B`, comments: [{text: `Comment`, comments: [
//       {text: 'foo', comments: []}, 
//       {text: 'bar', comments: []}
//     ]}]},
//     {topic: `Topic C`, comments: []}
//   ],
//   otherstuff: {}
// }
<script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.26.1/ramda.js"></script>
<script>const {over, lensPath, intersperse, append} = R            </script>

这里我们使用的路径是[1, 0],代表第二篇帖子(索引 1)和其中的第一条评论(索引 0)。

我们可以写更多更复杂的lens https://ramdajs.com/docs/#lens如果路径不够,则遍历对象。

我不知道这是否是一个整体的改进,但这绝对是对 Ramda 的更合适的使用。 (免责声明:我是 Ramda 的作者之一。)

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

通过引用更新树结构中的项目并返回更新后的树结构 的相关文章

随机推荐