我在chrome控制台中有一个警告:
Warning: Cannot update during an existing state transition (such as within `render`). Render methods should be a pure function of props and state.
in div (at Search.jsx:37)
in Search (at pages/index.jsx:79)
in main (created by Basic)
in Basic (created by Context.Consumer)
in Content (at pages/index.jsx:78)
in section (created by Context.Consumer)
in BasicLayout (created by Context.Consumer)
...代码按预期工作。它是Flexsearch的一种反应式实现,它是Web上最快、内存最多的全文搜索库.但这个警告让我心烦。
我在这方面做了很多工作,没有找到适当的解决办法。
Search.jsx:
/**
* Vendor Import
*/
import React from 'react';
import _find from 'lodash/find';
import _map from 'lodash/map';
import _isEmpty from 'lodash/isEmpty';
import _isEqual from 'lodash/isEqual';
import NotFound from '../images/notfound.svg';
import { Col, Row } from 'antd';
/**
* Component import
*/
import ProductList from '../components/ProductList';
/**
* Utils import
*/
import { filterData } from '../utils/filterdata';
import ContextConsumer from '../utils/context';
/**
* Style import
*/
import './search.css';
class Search extends React.Component {
state = {
query: '',
results: this.props.groupedData,
};
render() {
return (
<div className={this.props.classNames}>
<ContextConsumer>
{({ data }) => {
this.handleSearch(data.query);
}}
</ContextConsumer>
<div className='search__list'>
{!_isEmpty(this.state.results) ? (
<ProductList products={this.state.results} />
) : (
<Row>
<Col span={24} className='no_results'>
No results corresponding to "<b>{this.state.query}</b>"
</Col>
<Col xs={24} sm={12} md={8} lg={6} className='no_results'>
<NotFound />
</Col>
</Row>
)}
</div>
</div>
);
}
/**
* Handle search
* @param {String} query
*/
handleSearch = (query) => {
if (!_isEqual(this.state.query, query)) {
const groupedData = this.props.groupedData;
const results = this.getSearchResults(groupedData, query);
this.setState({ results: results, query: query });
}
};
/**
* Get the data associated to the query
* @param {Array} data
* @param {String} query
*/
getSearchResults(data, query) {
const index = window.__FLEXSEARCH__.en.index;
const store = window.__FLEXSEARCH__.en.store;
if (!query || !index) {
return data;
} else {
let resultingNodesID = [];
Object.keys(index).forEach((idx) => {
resultingNodesID.push(...index[idx].values.search(query));
});
resultingNodesID = Array.from(new Set(resultingNodesID));
const resultingNodes = store
.filter((node) => (resultingNodesID.includes(node.id) ? node : null))
.map((node) => node.node);
const resultingGroupedData = [];
_map(resultingNodes, (node) => {
resultingGroupedData.push(_find(data, { ref: node.ref }));
});
return resultingGroupedData;
}
}
/**
* Invoked immediately after updating occurs.
* @param prevProps
*/
componentDidUpdate(prevProps) {
const { selectedMenu, groupedData } = this.props;
if (!_isEqual(prevProps.selectedMenu, selectedMenu)) {
const filteredData = filterData(groupedData, selectedMenu);
const results = filteredData;
this.setState({ results: results });
}
}
}
export default Search;ContextProviderComponent:
/**
* Vendor Import
*/
import React from 'react';
const defaultContextValue = {
data: {
// set your initial data shape here
query: '',
},
set: () => {},
};
const { Provider, Consumer } = React.createContext(defaultContextValue);
class ContextProviderComponent extends React.Component {
constructor() {
super();
this.setData = this.setData.bind(this);
this.state = {
...defaultContextValue,
set: this.setData,
};
}
setData(newData) {
this.setState((state) => ({
data: {
...state.data,
...newData,
},
}));
}
render() {
return <Provider value={this.state}>{this.props.children}</Provider>;
}
}
export { Consumer as default, ContextProviderComponent };我做错什么了?
ps:如果你看到一些改进或无用的代码,我会全神贯注的!
发布于 2020-07-17 14:05:49
我找到了解决办法。
@关于这个问题的起源是正确的。他的回答帮助我重写了我的代码。
Search.jsx
/**
* Vendor Import
*/
import React from 'react';
import _isEmpty from 'lodash/isEmpty';
import _isEqual from 'lodash/isEqual';
import NotFound from '../images/notfound.svg';
import { Col, Row } from 'antd';
/**
* Component import
*/
import ProductList from './ProductList';
/**
* Utils import
*/
import { filterData } from '../utils/filterdata';
import { SearchContext } from '../utils/searchcontext';
import { getSearchResults } from '../utils/getsearchresults';
/**
* Style import
*/
import './search.css';
class Search extends React.Component {
constructor(props) {
super(props);
this.state = { results: this.props.groupedData, query: '' };
}
previousContext = '';
/**
* Invoked immediately after a component is mounted.
*/
componentDidMount() {
//console.log('--- componentDidMount ---');
this.previousContext = this.context;
}
/**
* Invoked immediately after updating occurs.
* @param prevProps
*/
componentDidUpdate(prevProps) {
//console.log('--- componentDidUpdate ---');
const { selectedMenu, groupedData } = this.props;
if (!_isEqual(prevProps.selectedMenu, selectedMenu)) {
this.setState({ results: filterData(groupedData, selectedMenu) });
}
if (!_isEqual(this.previousContext, this.context)) {
let searchQuery = this.context;
this.setState({ results: getSearchResults(groupedData, searchQuery) });
}
this.previousContext = this.context;
}
render() {
let searchQuery = this.context;
return (
<div className={this.props.classNames}>
<div className='search__list'>
{!_isEmpty(this.state.results) ? (
<ProductList products={this.state.results} />
) : (
<Row>
<Col span={24} className='no_results'>
Pas de résultats correspondants à "<b>{searchQuery}</b>"
</Col>
<Col xs={24} sm={12} md={8} lg={6} className='no_results'>
<NotFound />
</Col>
</Row>
)}
</div>
</div>
);
}
}
Search.contextType = SearchContext;
export default Search;getseatchresults.js
/**
* Vendor Import
*/
import _find from 'lodash/find';
import _map from 'lodash/map';
/**
* Get the results from search
* @param {Array} data
* @param {String} query
*/
export const getSearchResults = (data, query) => {
const index = window.__FLEXSEARCH__.en.index;
const store = window.__FLEXSEARCH__.en.store;
if (!query || !index) {
return data;
} else {
let resultingNodesID = [];
Object.keys(index).forEach((idx) => {
resultingNodesID.push(...index[idx].values.search(query));
});
resultingNodesID = Array.from(new Set(resultingNodesID));
const resultingNodes = store
.filter((node) => (resultingNodesID.includes(node.id) ? node : null))
.map((node) => node.node);
const resultingGroupedData = [];
_map(resultingNodes, (node) => {
resultingGroupedData.push(_find(data, { ref: node.ref }));
});
return resultingGroupedData;
}
};searchcontext.js
/**
* Vendor Import
*/
import React from 'react';
/**
* This context is for the Search query. It provides a query from the search bar in MyLayout.jsx to the Search.jsx component.
* Due to the impossibility to pass props from the Layout to other components, a context has to be used.
*/
export const SearchContext = React.createContext('');以下是我所做的:
前一个上下文组件不是我的。这是Gatsby柔性搜索插件集成的通用样板。我不明白代码的意图。所以我检查了React并阅读了所有上下文部分。然后,我简化了代码,将搜索逻辑导出到Search.jsx组件之外,并简化了最后一个组件。
发布于 2020-07-15 14:50:41
当它要求您的呈现函数是纯的,它希望它不更新状态。它也不应该调用任何更新状态的东西。
在search.jsx中,调用this.handleSearch()在渲染中。handleSearch()调用this.setState()。在通过上下文提供程序传递数据之前,您需要处理这个搜索逻辑。(因此,将搜索处理逻辑移到ContextProviderComponent并将搜索结果放到上下文中),或者您需要侦听呈现函数之外的上下文更改。这的答案给出了很多方法来做到这一点。
至于代码质量,在我快速查看您的代码时,我没有看到任何明显的危险信号,所以做得很好!你似乎有反应的基本要素。
https://stackoverflow.com/questions/62917104
复制相似问题