【问题标题】:How to refer to the current state in FP?如何在 FP 中引用当前状态?
【发布时间】:2020-10-11 14:51:12
【问题描述】:

我已经问过这个问题,但我的解释很糟糕,所以我决定用更好的解释和实际代码再次提问(我会要求版主删除其中一个帖子)。所以让我们考虑一下这个问题。

下面的 sn-p 表示从数组中渲染注释。然而,在添加注释部分,我改变了一个状态。所以问题是:如何在notes 数组中添加新注释而不发生变异?换句话说,我想删除replaceNotes 并保持相同的功能。我知道完全可以在没有数组的情况下添加注释,但是由于将来的参考,我确实需要使用注释更新数组。问题是,在我的原始应用程序中,我有带有注释的列表,当我在列表之间切换时,我应该得到依赖于我打开的列表的渲染注释。这就是为什么我应该保留对 notes 数组的引用。

同时我想知道,如果我只是将notes 存储在localStorage 中,然后从该数据中做笔记,可以吗?这是函数式编程的好习惯吗?

const button = document.getElementById('button');
const notesContainer = document.querySelector('.notes');

const pipe = (f, g) => (...args) => f(g(...args));

let notes = [];

const createNote = (...fns) => fns.reduceRight(pipe);

const handleEvent = () =>
   createNote(gatherContent, renderContent, replaceNotes)(notes);

function gatherContent(notes) {
   const name = prompt('How do you want to name a note?');

   return [...notes, { name }];
}

function renderContent(notes) {
   function render(note) {
      const noteEl = document.createElement('div');
      noteEl.innerHTML = `<p>${note.name}</p>`;
      notesContainer.append(noteEl);
   }

   notesContainer.innerHTML = '';
   notes.map(render);

   return notes;
}

const replaceNotes = newNotes => (notes = newNotes);

button.addEventListener('click', handleEvent);
<button id="button">Click me!</button>
<section class="notes"></section>

【问题讨论】:

  • 认为你对pipe的定义在函数式编程世界中被称为compose
  • 我的意思是,如果我在createNote 中更改函数作为参数的顺序并将reduceRight 替换为reduce,这将是组合,不是吗?
  • 我的理解是pipe(f, g)(x) = g(f(x))compose(f, g)(x) = f(g(x)) 是很常见的。
  • 确实如此。起初我想这样写,但后来我的脑海里突然出现了一些东西,我写了reduceRightlmao
  • 您应该可以删除自己的帖子?

标签: javascript functional-programming state immutability mutation


【解决方案1】:

这里是如何创建一个简单的任务列表应用程序,而不需要改变除 DOM 之外的任何内容。

const button = document.getElementById("button");
const section = document.getElementById("notes");
const template = document.getElementById("template");

template.parentNode.removeChild(template);

const render = notes => {
    button.onclick = event => {
        const name = prompt("How do you want to name a note?");
        render([...notes, { name }]);
    };

    while (section.lastChild) {
        section.removeChild(section.lastChild);
    }

    for (const note of notes) {
        const node = template.cloneNode(true);
        node.firstChild.firstChild.nodeValue = note.name;
        section.appendChild(node);
    }
};

render([]);
<button id="button">Click me!</button>
<section id="notes"></section>
<div id="template"><p>name</p></div>

如需详细解释,请阅读我之前的回答。 https://stackoverflow.com/a/58642199/783743


您也可以将此模式与localStorage 一起使用。

const button = document.getElementById("button");
const section = document.getElementById("notes");
const template = document.getElementById("template");

template.parentNode.removeChild(template);

const render = notes => {
    localStorage.setItem("notes", notes); // set notes

    button.onclick = event => {
        const name = prompt("How do you want to name a note?");
        render([...notes, { name }]);
    };

    while (section.lastChild) {
        section.removeChild(section.lastChild);
    }

    for (const note of notes) {
        const node = template.cloneNode(true);
        node.firstChild.firstChild.nodeValue = note.name;
        section.appendChild(node);
    }
};

render(localStorage.getItem("notes") || []); // get notes

请注意,localStorage 只能用于保存您希望跨会话使用的状态。不建议使用localStorage 作为您的应用商店。这会导致性能不佳和代码结构不佳。

【讨论】:

  • 这是解决此类问题的一种有趣方式,我肯定会在某些地方使用它。但我仍然想知道在函数式编程中使用localStorage 是一种好习惯吗?就我而言,这似乎是最佳选择
  • 不要将localStorage 用作您的应用程序商店。我编辑了答案以解释原因。
  • 谢谢!你的解释很有帮助。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-31
  • 2023-03-03
  • 2015-06-19
  • 1970-01-01
  • 2017-12-01
  • 2020-06-14
相关资源
最近更新 更多