diff --git a/src/types/YText.js b/src/types/YText.js
index e16ad5b9..328795e0 100644
--- a/src/types/YText.js
+++ b/src/types/YText.js
@@ -706,9 +706,9 @@ export class YTextEvent extends YEvent {
                       addOp()
                     }
                     if (value === null) {
-                      attributes[key] = value
-                    } else {
                       delete attributes[key]
+                    } else {
+                      attributes[key] = value
                     }
                   } else {
                     item.delete(transaction)
diff --git a/tests/y-text.tests.js b/tests/y-text.tests.js
index 100d619a..d16bc0a7 100644
--- a/tests/y-text.tests.js
+++ b/tests/y-text.tests.js
@@ -288,6 +288,41 @@ export const testFormattingRemovedInMidText = tc => {
   t.assert(Y.getTypeChildren(text0).length === 3)
 }
 
+/**
+ * Reported in https://github.com/yjs/yjs/issues/344
+ *
+ * @param {t.TestCase} tc
+ */
+export const testFormattingDeltaUnnecessaryAttributeChange = tc => {
+  const { text0, text1, testConnector } = init(tc, { users: 2 })
+  text0.insert(0, '\n', {
+    PARAGRAPH_STYLES: 'normal',
+    LIST_STYLES: 'bullet'
+  })
+  text0.insert(1, 'abc', {
+    PARAGRAPH_STYLES: 'normal'
+  })
+  testConnector.flushAllMessages()
+  /**
+   * @type {Array<any>}
+   */
+  const deltas = []
+  text0.observe(event => {
+    deltas.push(event.delta)
+  })
+  text1.observe(event => {
+    deltas.push(event.delta)
+  })
+  text1.format(0, 1, { LIST_STYLES: 'number' })
+  testConnector.flushAllMessages()
+  const filteredDeltas = deltas.filter(d => d.length > 0)
+  t.assert(filteredDeltas.length === 2)
+  t.compare(filteredDeltas[0], [
+    { retain: 1, attributes: { LIST_STYLES: 'number' } }
+  ])
+  t.compare(filteredDeltas[0], filteredDeltas[1])
+}
+
 /**
  * @param {t.TestCase} tc
  */