无法设置反应功能组件的状态

时间:2020-05-10 10:53:15

标签: reactjs react-hooks vega vega-lite

期望值:单击按钮->更改变量值->重新渲染

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

我正在寻找最简单的方法来解决此问题。我相信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$1 (0.chunk.js:59160)
    discreteUpdates (0.chunk.js:38222)
    dispatchDiscreteEvent (0.chunk.js:41621)
    dispatchDiscreteEvent

1 个答案:

答案 0 :(得分:1)

用钩子更新的

state不会合并值,而是会覆盖它们。

来自official docs

与类组件中的setState方法不同,useState确实可以 不会自动合并更新对象。您可以复制此 通过将功能更新程序形式与对象传播相结合来实现行为 语法:

您需要在更新时自行合并值。在您的情况下,您只需运行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>
  );