好的,所以我在为ChartJS创建React组件方面做得很好,但是在测试时我得到以下错误:
FAIL lib\chart\chart.test.tsx
● renders without crashing
TypeError: Cannot read property 'length' of null
at Object.acquireContext (node_modules/chart.js/src/platforms/platform.dom.js:189:19)
at Chart.construct (node_modules/chart.js/src/core/core.controller.js:72:27)
at new Chart (node_modules/chart.js/src/core/core.js:7:8)
at Chart.Object.<anonymous>.Chart.renderChart (lib/chart/chart.tsx:233:26)
at Chart.Object.<anonymous>.Chart.componentDidMount (lib/chart/chart.tsx:42:10)
at node_modules/react-dom/lib/ReactCompositeComponent.js:264:25
at measureLifeCyclePerf (node_modules/react-dom/lib/ReactCompositeComponent.js:75:12)
at node_modules/react-dom/lib/ReactCompositeComponent.js:263:11
at CallbackQueue.notifyAll (node_modules/react-dom/lib/CallbackQueue.js:76:22)
at ReactReconcileTransaction.close (node_modules/react-dom/lib/ReactReconcileTransaction.js:80:26)
at ReactReconcileTransaction.closeAll (node_modules/react-dom/lib/Transaction.js:209:25)
at ReactReconcileTransaction.perform (node_modules/react-dom/lib/Transaction.js:156:16)
at batchedMountComponentIntoNode (node_modules/react-dom/lib/ReactMount.js:126:15)
at ReactDefaultBatchingStrategyTransaction.perform (node_modules/react-dom/lib/Transaction.js:143:20)
at Object.batchedUpdates (node_modules/react-dom/lib/ReactDefaultBatchingStrategy.js:62:26)
at Object.batchedUpdates (node_modules/react-dom/lib/ReactUpdates.js:97:27)
at Object._renderNewRootComponent (node_modules/react-dom/lib/ReactMount.js:319:18)
at Object._renderSubtreeIntoContainer (node_modules/react-dom/lib/ReactMount.js:401:32)
at Object.render (node_modules/react-dom/lib/ReactMount.js:422:23)
at Object.<anonymous> (lib/chart/chart.test.tsx:7:12)
at Promise (<anonymous>)
at Promise.resolve.then.el (node_modules/p-map/index.js:42:16)
at <anonymous>
at process._tickCallback (internal/process/next_tick.js:169:7)
× renders without crashing (275ms)
Test Suites: 1 failed, 1 total
Tests: 1 failed, 1 total
Snapshots: 0 total
Time: 1.314s, estimated 3s
Ran all test suites related to changed files.
然而,我花了很长时间查看代码并且无法找出它拒绝正常工作的原因。在创建新图表实例时,错误从renderChart()
函数开始。我的第一个猜测是由于某些原因,它没有注册canvas元素,尽管它被id调用。但是当renderChart的内容被移动到render()函数中时,它仍会给出相同的错误。这是测试的代码:
import * as React from 'react'
import * as ClassNames from 'classnames'
import * as ChartJS from 'chart.js'
const IsEqual = require('lodash.isequal')
const Find = require('lodash.find')
const subChart = require('chart.js')
interface IChartProps {
/** The user-defined classes */
readonly className?: string
readonly width?: number
readonly height?: number
readonly reRender?: boolean
readonly type: ChartJS.ChartType
readonly data: ChartJS.ChartData
readonly options: ChartJS.ChartOptions
readonly getDatasetAtEvent?: Function
readonly getElementAtEvent?: Function
readonly getElementsAtEvent?: Function
readonly onElementsClick?: Function
readonly datasetKeyProvider?: Function
}
interface IChartState {
/** Add your states here */
}
export class Chart extends React.Component<IChartProps, IChartState> {
// tslint:disable-next-line
private chartInstance: any
private shadowData: {}
constructor(props: IChartProps) {
super(props)
}
public componentWillMount() {
// this.chartInstance = undefined
}
public componentDidMount() {
this.renderChart()
}
// public componentWillReceiveProps(nextProps: IChartProps) {}
public shouldComponentUpdate(nextProps: IChartProps, nextState: IChartState) {
const props = this.props
if (nextProps.reRender === true) {
return true
}
if (props.height !== nextProps.height || props.width !== nextProps.width) {
return true
}
if (props.type !== nextProps.type) {
return true
}
if (!IsEqual(props.options, nextProps.options)) {
return true
}
const nextData = this.transformDataProp(nextProps)
if (!IsEqual(this.shadowData, nextData)) {
return true
}
return false
}
// public componentWillUpdate(nextProps: IChartProps, nextState: IChartState) {}
public componentDidUpdate(prevProps: IChartProps, prevState: IChartState) {
if (this.props.reRender) {
this.chartInstance.destroy()
this.renderChart()
return
}
this.updateChart()
}
public transformDataProp(props: IChartProps) {
const data = props.data
if (typeof data === 'function') {
const node = document.getElementById('bar-chart') as HTMLCanvasElement
return data(node)
} else {
return data
}
}
public memoizeDataProps(props?: IChartProps) {
if (!this.props.data) {
return
}
const data = this.transformDataProp(this.props)
this.shadowData = {
...data,
datasets:
data.datasets &&
data.datasets.map((set: string[]) => {
return { ...set }
})
}
return data
}
public updateChart() {
const options = this.props.options
const data = this.memoizeDataProps(this.props)
if (!this.chartInstance) {
return
}
if (options) {
this.chartInstance.options = subChart.helpers.configMerge(
this.chartInstance.options,
options
)
}
let currentDatasets =
(this.chartInstance.config.data &&
this.chartInstance.config.data.datasets) ||
[]
const nextDatasets = data.datasets || []
const currentDatasetKeys = currentDatasets.map(
this.props.datasetKeyProvider
)
const nextDatasetKeys = nextDatasets.map(this.props.datasetKeyProvider)
const newDatasets = nextDatasets.filter(
(d: object) =>
currentDatasetKeys.indexOf(this.props.datasetKeyProvider(d)) === -1
)
for (let idx = currentDatasets.length - 1; idx >= 0; idx -= 1) {
const currentDatasetKey = this.props.datasetKeyProvider(
currentDatasets[idx]
)
if (nextDatasetKeys.indexOf(currentDatasetKey) === -1) {
// deleted series
currentDatasets.splice(idx, 1)
} else {
const retainedDataset = Find(
nextDatasets,
(d: object) => this.props.datasetKeyProvider(d) === currentDatasetKey
)
if (retainedDataset) {
// update it in place if it is a retained dataset
currentDatasets[idx].data.splice(retainedDataset.data.length)
retainedDataset.data.forEach((point: number, pid: number) => {
currentDatasets[idx].data[pid] = retainedDataset.data[pid]
})
// const { data, ...otherProps } = retainedDataset
currentDatasets[idx] = {
data: currentDatasets[idx].data,
...currentDatasets[idx],
...retainedDataset.otherProps
}
}
}
}
// finally add any new series
newDatasets.forEach((d: object) => currentDatasets.push(d))
const { datasets, ...rest } = data
this.chartInstance.config.data = {
...this.chartInstance.config.data,
...rest
}
this.chartInstance.update()
}
public componentWillUnmount() {
this.chartInstance.destroy()
}
public onClickEvent = (event: React.MouseEvent<HTMLCanvasElement>) => {
// this.props.getDatasetAtEvent &&
this.props.getDatasetAtEvent(
this.chartInstance.getDatasetAtEvent(event),
event
)
// this.props.getElementAtEvent &&
this.props.getElementAtEvent(
this.chartInstance.getElementAtEvent(event),
event
)
// this.props.getElementsAtEvent &&
this.props.getElementsAtEvent(
this.chartInstance.getElementsAtEvent(event),
event
)
// this.props.onElementsClick &&
this.props.onElementsClick(
this.chartInstance.getElementsAtEvent(event),
event
)
}
public render() {
const className = ClassNames('chart', this.props.className)
// bar.update()
return (
<div className={className}>
<canvas
id="chart-instance"
width={this.props.width ? this.props.width : '400'}
height={this.props.height ? this.props.height : '400'}
onClick={this.onClickEvent}
/>
</div>
)
}
public renderChart() {
const { options, type, data } = this.props
const node = document.getElementById('chart-instance') as HTMLCanvasElement
// const data = this.memoizeDataProps()
this.chartInstance = new ChartJS(node, {
type,
data,
options
})
}
}
有人可以帮我弄清楚为什么这不能正常工作吗?
答案 0 :(得分:0)
可能因为这个原因:
currentDatasets[idx].data.splice(retainedDataset.data.length)
您还应该检查retainedDataset.data
:
if (retainedDataset && retainedDataset.data) { ... }