无法为 React 功能组件设置状态

Failed to set state for react functional component

预期结果:单击按钮 -> 更改变量值 -> 重新呈现

发生了什么:单击了按钮 -​​> 错误

我正在寻找解决此问题的最直接方法。我相信 redux 可能会有所帮助。

我从 yarn create react

创建了项目
import React, { useState } from 'react';
import { VegaLite } from 'react-vega'

var specDefault = {
  width: 400,
  height: 200,
  mark: 'bar',
  encoding: {
    x: { field: 'a', type: 'ordinal' },
    y: { field: 'b', type: 'quantitative' },
  },
  data: { name: 'table' },
}

const barData = {
  table: [
    { a: 'A', b: 28 },
    { a: 'B', b: 55 },
    { a: 'C', b: 43 },
    { a: 'D', b: 91 },
    { a: 'E', b: 81 },
    { a: 'F', b: 53 },
    { a: 'G', b: 19 },
    { a: 'H', b: 87 },
    { a: 'I', b: 52 },
  ],
}

function UpdateSpec(props) {
  const [spec, setSpec] = useState(specDefault);

  return (
    <div>
      <button onClick={() => setSpec(spec.mark = 'line')}>
        Change to Line Chart
      </button>
      <VegaLite spec={spec} data={barData} />
    </div>
  );
}

function App() {
  return (
    <>
      {UpdateSpec()}
    </>

  );
}

export default App;

错误:

[Error] TypeError: newSpec is not an Object. (evaluating ''width' in newSpec')
    computeSpecChanges (0.chunk.js:65101)
    componentDidUpdate (0.chunk.js:64784:101)
    commitLifeCycles (0.chunk.js:57118)
    commitLayoutEffects (0.chunk.js:60070)
    callCallback (0.chunk.js:37600)
    dispatchEvent
    invokeGuardedCallbackDev (0.chunk.js:37649)
    invokeGuardedCallback (0.chunk.js:37702)
    commitRootImpl (0.chunk.js:59812)
    commitRootImpl
    unstable_runWithPriority (0.chunk.js:68183)
    commitRoot (0.chunk.js:59654)
    finishSyncRender (0.chunk.js:59071)
    performSyncWorkOnRoot (0.chunk.js:59057)
    performSyncWorkOnRoot
    (anonymous function) (0.chunk.js:48541)
    unstable_runWithPriority (0.chunk.js:68183)
    flushSyncCallbackQueueImpl (0.chunk.js:48536)
    flushSyncCallbackQueue (0.chunk.js:48524)
    discreteUpdates (0.chunk.js:59160)
    discreteUpdates (0.chunk.js:38222)
    dispatchDiscreteEvent (0.chunk.js:41621)
    dispatchDiscreteEvent

state 使用挂钩更新不会合并值,而只是覆盖它们。

来自official docs

Unlike the setState method found in class components, useState does not automatically merge update objects. You can replicate this behavior by combining the function updater form with object spread syntax:

您需要在更新时自行合并值。在您的情况下,您只是用 line 替换了整个状态 运行 setSpec(spec.mark = 'line')。您可以像下面这样使用 functional state update

return (
    <div>
      <button onClick={() => setSpec(prev => ({...prev, mark:'line'}))}>
        Change to Line Chart
      </button>
      <VegaLite spec={spec} data={barData} />
    </div>
  );