- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我正在尝试测试我的组件“CBreadcrumb”,它使用“withRouter”HOC。运行测试用例时,所有测试用例都通过,但显示警告。
我已经多次尝试检查我的代码。但我无法找到警告的原因。我也尝试过研究这些答案,但没有帮助我。
Can't perform a React state update on an unmounted component
React warning about setState in unmounted component
CBreadcrumb 组件
import React, {PureComponent} from 'react';
import Proptypes from 'prop-types';
import Breadcrumb from "react-bootstrap/Breadcrumb";
import {withRouter} from 'react-router-dom';
import {TryCatchHandler} from "../../../common-utils";
class CBreadcrumb extends PureComponent {
state = {
routes: [],
currentLocation: ""
};
setCurrentLocation = path => {
this.setState({currentLocation: path});
};
setRoutes = routes => {
this.setState({routes: routes});
};
/**
* GETS ARRAY OF PATH(URL) UPTO CURRENT PAGE
* @returns {string[]}
*/
getPathsToInclude = () => {
let currentLocation = !this.state.currentLocation ?
this.props.location.pathname : this.state.currentLocation;
// GET AVAILABLE PATHS IN CURRENT PAGE URL
let pathsToInclude = ((currentLocation).split('/'));
// REMOVE THE FIRST EMPTY ELEMENT FROM ARRAY
pathsToInclude.shift();
// IF ROUTE IS NOT 'home' ADD 'home' AS FIRST PATH
pathsToInclude[0] !== "home" && pathsToInclude.unshift("home");
//INCLUDE '/' IN EACH PATHNAME
for (let i = 0; i < pathsToInclude.length; i++) {
i === 0 || i === 1 ? pathsToInclude[i] = "/".concat(pathsToInclude[i])
: pathsToInclude[i] = pathsToInclude[i - 1] + "/".concat(pathsToInclude[i])
}
return pathsToInclude;
};
/**
*
* @param pathsToInclude
* @returns {Array}
*/
addRoutesByPathsToInclude = pathsToInclude => {
let routes = [];
pathsToInclude.forEach(value => {
routes = routes.concat(
this.props.breadcrumbData
.filter(breadCrumb =>
breadCrumb.path === value
));
});
return routes;
};
filterAndSetRoutesUptoCurrentPage = () => {
this.setRoutes(this.addRoutesByPathsToInclude(this.getPathsToInclude()));
};
setCurrentLocationAndFilterRoutes = async path => {
!path ? await this.setCurrentLocation(this.props.location.pathname)
: await this.setCurrentLocation(path);
this.filterAndSetRoutesUptoCurrentPage();
};
componentDidMount() {
TryCatchHandler.genericTryCatch(this.setCurrentLocationAndFilterRoutes());
}
componentDidUpdate(prevProps, prevState, snapshot) {
/**
* SINCE IT IS LIFECYCLE METHOD , IT RUNS WITH EVERY TEST.
* IN TEST WE DON'T HAVE ACCESS TO 'withRouter' SO IT WILL HAVE TO
* BE SET MANUALLY IN FEW REQUIRED TEST CASES ONLY.
* SO FOR OTHER TESTS WHERE THE PROPS ARE NOT SET,
* 'location' and 'history' OBJECT WILL NOT BE AVAILABLE RESULTING IN WHOLE TEST SUITE FAILURE.
*/
if (prevProps.history) {
const newPath = prevProps.history.location.pathname;
const oldPath = prevProps.location.pathname;
if (newPath !== oldPath) {
TryCatchHandler.genericTryCatch(this.setCurrentLocationAndFilterRoutes(newPath));
} else {
return false
}
} else {
return false
}
}
createBreadcrumbLink = (breadcrumb, index) =>
index !== this.state.routes.length - 1 ?
{'href': "#".concat(breadcrumb.path)} : {'active': true};
getBreadcrumbItemProps = (breadcrumb, index) => {
const {itemAs, title, target, itemBsPrefix, itemChildren} = this.props;
return (
{
'key': "breadcrumb" + breadcrumb.id,
'id': "breadcrumbItem" + breadcrumb.id,
'as': itemAs,
'title': title,
'target': target,
'bsPrefix': itemBsPrefix,
'children': itemChildren,
...this.createBreadcrumbLink(breadcrumb, index)
}
);
};
getBreadcrumbItems = (breadcrumb, index) =>
<Breadcrumb.Item
{...this.getBreadcrumbItemProps(breadcrumb, index)}
>
{breadcrumb.name}
</Breadcrumb.Item>;
render() {
const {as, label, listProps, bsPrefix, children} = this.props;
return (
<Breadcrumb
as={as}
label={label}
listProps={listProps}
bsPrefix={bsPrefix}
children={children}
>
{this.state.routes.map((breadcrumb, index) => (
this.getBreadcrumbItems(breadcrumb, index)
))}
</Breadcrumb>);
}
}
React.propTypes = {
breadcrumbData: Proptypes.array.isRequired,
as: Proptypes.elementType,
label: Proptypes.string,
bsPrefix: Proptypes.string,
listProps: Proptypes.object,
children: Proptypes.array,
title: Proptypes.node,
target: Proptypes.string,
href: Proptypes.string,
active: Proptypes.boolean,
itemAs: Proptypes.elementType,
itemBsPrefix: Proptypes.string,
itemChildren: Proptypes.array
};
/**
* 'withRouter' IS A HIGHER ORDER COMPONENT PROVIDED BY 'react-router-dom'.
* 'withRouter' WILL PASS UPDATED 'match', 'location', and 'history' PROPS
* TO THE WRAPPED COMPONENT WHENEVER IT RENDERS.
* IN BREADCRUMB COMPONENT IT IS USED TO DETECT THE ROUTE CHANGE ALONG WITH 'componentDidUpdate' LIFECYCLE METHOD.
*/
export default withRouter(CBreadcrumb);
CBreadcrumb.test.js
import React from "react";
import CBreadcrumb from '../CBreadcrumb';
expect.addSnapshotSerializer(enzymeSerializer);
describe('CBreadcrumb component tests', () => {
let wrapper, instance;
const dataForBreadCrumb = [
{
id: '1',
name: 'Home',
path: '/home'
},
{
id: '2',
name: 'General Setup',
path: '/generalSetup'
}];
let setWrapperProps = (cWrapper, propsObject) => {
cWrapper.setProps(propsObject);
};
describe('Breadcrumb Component Tests', () => {
beforeEach(() => {
wrapper = shallow(<CBreadcrumb.WrappedComponent/>);
setWrapperProps(wrapper, {breadcrumbData: []});
});
test('if CBreadcrumb component is defined', () => {
expect(wrapper).toBeDefined();
});
test('if renders Breadcrumb component', () => {
expect(wrapper.find('Breadcrumb').length).toEqual(1);
});
test('if Breadcrumb component contains all required props', () => {
let propRequired = [
'as',
'label',
'listProps',
'bsPrefix',
'children'
];
let propsAvailableForBreadcrumb = Object.keys(wrapper.find('Breadcrumb').props());
propRequired.forEach((propAvail, i) => (
expect(propAvail).toContain(propsAvailableForBreadcrumb[i])
));
});
});
describe('CBreadcrumb state tests', () => {
beforeEach(() => {
wrapper = mount(<CBreadcrumb.WrappedComponent/>);
instance = wrapper.instance();
setWrapperProps(wrapper, {breadcrumbData: dataForBreadCrumb});
});
afterEach(() => {
wrapper.unmount();
});
test('if routes state is defined', () => {
expect(wrapper.state('routes')).toBeDefined();
});
test('if currentLocation state is defined', () => {
expect(wrapper.state('currentLocation')).toBeDefined();
});
test('if state`s property currentLocation is set after componentDidMount', () => {
setWrapperProps(wrapper, {
location: {
pathname: '/generalSetup'
},
history: {
location: {
pathname: ''
}
}
});
jest.spyOn(instance, 'setCurrentLocation');
instance.componentDidMount();
expect(instance.setCurrentLocation).toHaveBeenCalled();
});
test('if routes are filtered upto current location and ' +
'state`s property routes is set after componentDidMount ', async () => {
// jest.spyOn(instance, 'setRoutes');
setWrapperProps(wrapper, {location: {pathname: '/generalSetup'}});
await instance.componentDidMount();
// wrapper.update();
expect(wrapper.state('routes').length).not.toBe(0);
});
test('if componentDidUpdate lifecycle will be called and ' +
'routes will be filtered when url changes', async () => {
await instance.componentDidUpdate({
location: {
pathname: '/generalSetup'
},
history: {
location: {
pathname: '/home'
}
}
});
expect(wrapper.state('routes').length).toBe(1);
});
});
describe('BreadcrumbItem Component Tests', () => {
beforeEach(async () => {
wrapper = shallow(<CBreadcrumb.WrappedComponent/>);
instance = wrapper.instance();
setWrapperProps(wrapper, {
breadcrumbData: dataForBreadCrumb,
location: {
pathname: '/generalSetup'
},
});
await instance.componentDidMount();
wrapper.update();
});
test('if renders BreadcrumbItem component', () => {
expect(wrapper.find('#breadcrumbItem1').length).toBe(1);
});
test('if BreadcrumbItem component shows name', () => {
expect(wrapper.find('#breadcrumbItem1').text()).not.toBe('');
});
test('if BreadcrumbItem components except last has href with value', () => {
expect(wrapper.find('#breadcrumbItem1').prop('href')).not.toBe('');
});
test('if last BreadcrumbItem component defined', () => {
expect(wrapper.find('#breadcrumbItem2').length).toBe(1);
});
test('if last BreadcrumbItem component has no href', () => {
expect(wrapper.find('#breadcrumbItem2').prop('href')).not.toBeDefined();
});
test('if last BreadcrumbItem component has prop active', () => {
expect(wrapper.find('#breadcrumbItem2').prop('active')).toBeTruthy();
});
test('if BreadcrumbItem component excluding last contains all required props', () => {
let propRequired = [
'test-id',
'as',
'title',
'target',
'bsPrefix',
'children',
'href'
];
let propsAvailableForBreadcrumbItem = Object.keys(wrapper.find('#breadcrumbItem1').props());
propRequired.forEach((propAvail, i) => (
expect(propAvail).toContain(propsAvailableForBreadcrumbItem[i])
));
});
test('if BreadcrumbItem component including last contains all required props', () => {
let propRequired = [
'test-id',
'as',
'title',
'target',
'bsPrefix',
'children',
'active'
];
let propsAvailableForBreadcrumbItem = Object.keys(wrapper.find('#breadcrumbItem2').props());
propRequired.forEach((propAvail, i) => (
expect(propAvail).toContain(propsAvailableForBreadcrumbItem[i])
));
});
});
describe('Snapshot Testing', () => {
wrapper = shallow(<CBreadcrumb.WrappedComponent breadcrumbData={dataForBreadCrumb}/>);
test('if renders CBreadcrumb component correctly', () => {
expect(wrapper).toMatchSnapshot();
});
});
});
App.js
import React from 'react';
import './App.css';
import {HashRouter, Switch, Route} from 'react-router-dom';
import CBreadcrumb from "./component/CBreadcrumb/CBreadcrumb";
import AdminSetupPage from "./component/AdminSetupPage/AdminSetupPage";
import {AddPage} from "./component/AdminSetupPage/AddPage";
function App() {
const dataForBreadCrumb = [
{
id: '1',
name: 'Home',
path: '/home'
},
{
id: '2',
name: 'General Setup',
path: '/generalSetup'
},
{
id: '3',
name: 'Admin Setup',
path: '/generalSetup/adminSetup'
},
{
id: '4',
name: 'Add Admin',
path: '/generalSetup/adminSetup/add'
},
{
id: '5',
name: 'Manage Admin',
path: '/generalSetup/adminSetup/manage'
},
];
return (
<HashRouter>
<CBreadcrumb breadcrumbData={dataForBreadCrumb}/>
<Switch>
<Route path="/generalSetup/adminSetup" component={AdminSetupPage}/>
<Route path='/generalSetup/adminSetup/add' component={AddPage}/>
</Switch>
</HashRouter>
);
}
export default App;
显示警告如下所示
console.error node_modules/react-dom/cjs/react-dom.development.js:506
Warning: Can't perform a React state update on an unmounted component. This is a no-op, but it indicates a memory leak in your application. To fix, cancel all subscriptions and asynchronous tasks in the componentWillUnmount method.
in CBreadcrumb (created by Context.Consumer)
in withRouter(CBreadcrumb) (created by App)
in Router (created by HashRouter)
in HashRouter (created by App)
in header (created by App)
in div (created by App)
in App
最佳答案
也许你可以引用this article 。在文章的最后,robinwieruh 建议通过 setState()
调用和 Component Unmount
问题解决此问题。
关于reactjs - 使用 Component.WrappedComponent 作为 withRouter 的替代品测试组件在运行测试用例时显示警告,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57388191/
我错过了什么,我已完成 的安装指南中要求的所有步骤 native 脚本 运行 tns doctor 给我以下输出... C:\abc\xyz>tns doctor √ Getting environm
尝试从 {addToCart(book)}}/>}> 传递数据至}> 问题: 购物车 ( render={()=> ) 收到 null,但没有收到我尝试发送的对象 已放置“console.log...
这是 _app.tsx 的外观: function MyApp({ Component, pageProps }: AppProps) { return } 我在构建项目时遇到了这个错误: Ty
我的 Laravel Vue 组件收到以下警告: [Vue warn]: Avoid mutating a prop directly since the value will be overwrit
根据这个example更详细this one我刚刚遇到了一件奇怪的事情...... 如果我使用方法作为 addTab(title,icon,component) 并且下一步想使用 setTabComp
目前我有一个捕获登录数据的表单,一个带有 TIWDBGrid 的表单,它应该返回与我从我的 mysql 数据库登录时创建的 user_id 关联的任何主机,以及一个共享数据模块。 下面是我的登录页面代
在我的react-native应用程序中,我目前有一个本地Android View (用java编写)正确渲染。当我尝试将我的react-native javascript 组件之一放入其中时,出现以
我为作业编写了简单的代码。我引用了文档和几个 youtube 视频教程系列。我的 react 代码是正确的我在运行代码时没有收到任何错误。但是这些 react-boostrap 元素没有渲染。此代码仅
几周前我刚刚开始使用 Flow,从一周前开始我就遇到了 Flow 错误,我不知道如何修复。 代码如下: // @flow import React, { Component } from "react
我想在同一个 View 中加载不同的 web2py 组件,但不是同时加载。我有 5 个 .load 文件,它们具有用于不同场景的表单字段,这些文件由 onchange 选择脚本动态调用。 web2py
关闭。这个问题是opinion-based .它目前不接受答案。 想改善这个问题吗?更新问题,以便可以通过 editing this post 用事实和引文回答问题. 6年前关闭。 Improve t
Blazor 有 InputNumber将输入限制为数字的组件。然而,这呈现了一个 firefox 不尊重(它允许任何文本)。 所以我尝试创建一个过滤输入的自定义组件: @inherits Inpu
我在学习 AngularDART 组件时编写了以下简单代码,但没有显示任何内容,任何人都可以帮助我知道我犯了什么错误: 我的 html 主文件:
我想在初始安装组件时或之后为 div 设置动画(淡入)。动画完成后,div 不应消失。我正在尝试使用 CSSTransition 组件并查看 reactcommunity.org 上的示例,但我根本无
我需要一个 JSF 组件来表示甘特图。是否有任何组件库(如 RichFaces)包含这样的组件? 最佳答案 JFreeChart有甘特图和PrimeFaces有一个图像组件,允许您动态地流式传输内容。
从软件工程的角度来看,组件、模块和子系统之间有什么区别? 提前致谢! 最佳答案 以下是 UML 2.5 的一些发现: 组件:该子句指定一组结构,可用于定义任意大小和复杂性的软件系统。特别是,它将组件指
我有使用非托管程序集(名为 unmanaged.dll)的托管应用程序(名为 managed.exe)。到目前为止,我们已经创建了 Interop.unmanaged.dll,managed.exe
我有一个跨多个应用程序复制的 DAL(我知道它的设计很糟糕,但现在忽略它),我想做的是这个...... 创建一个将通过所有桌面应用程序访问的 WCF DAL 组件。任何人都可以分享他们对关注的想法吗?
我有一个 ComboBox 的集合声明如下。 val cmbAll = for (i /** action here **/ } 所有这些都放在一个 TabbedPane 中。我想这不是问题。那么我
使用 VB6 创建一个 VB 应用程序。应用程序的一部分显示内部的闪存。 当我使用 printform它只是打印整个应用程序。我不知道如何单独打印闪光部分。任何帮助,将不胜感激!.. 谢谢。 最佳答案
我是一名优秀的程序员,十分优秀!