Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/450.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/reactjs/23.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 反应警告:无法在现有状态转换期间更新。搜索组件_Javascript_Reactjs_Search_Jsx - Fatal编程技术网

Javascript 反应警告:无法在现有状态转换期间更新。搜索组件

Javascript 反应警告:无法在现有状态转换期间更新。搜索组件,javascript,reactjs,search,jsx,Javascript,Reactjs,Search,Jsx,chrome devtools控制台中出现了一条警告: 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

chrome devtools控制台中出现了一条警告:

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的一个React实现,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;
/**
*供应商进口
*/
从“React”导入React;
从“lodash/find”导入查找;
从“lodash/map”导入地图;
从“lodash/isEmpty”进口;
从“lodash/isEqual”进口“isEqual”;
从“../images/NotFound.svg”导入NotFound;
从“antd”导入{Col,Row};
/**
*组件导入
*/
从“../components/ProductList”导入ProductList;
/**
*UTIL导入
*/
从“../utils/filterData”导入{filterData};
从“../utils/context”导入ContextConsumer;
/**
*样式导入
*/
导入“/search.css”;
类搜索扩展了React.Component{
状态={
查询:“”,
结果:此.props.groupedData,
};
render(){
返回(
{({data})=>{
this.handleSearch(data.query);
}}
{!\u是否空(this.state.results)(
) : (
没有与“{this.state.query}”对应的结果
)}
);
}
/**
*处理搜索
*@param{String}查询
*/
handleSearch=(查询)=>{
if(!\u isEqual(this.state.query,query)){
const groupedData=this.props.groupedData;
const results=this.getSearchResults(groupedData,查询);
this.setState({results:results,query:query});
}
};
/**
*获取与查询关联的数据
*@param{Array}数据
*@param{String}查询
*/
getSearchResults(数据、查询){
const index=window._FLEXSEARCH__.en.index;
const store=window._uflexsearch__.en.store;
如果(!查询| |!索引){
返回数据;
}否则{
让resultingNodesID=[];
Object.keys(index).forEach((idx)=>{
结果nodesid.push(…索引[idx].values.search(查询));
});
resultingNodesID=Array.from(新集合(resultingNodesID));
const resultingNodes=存储
.filter((节点)=>(结果节点id.includes(节点id)?节点:null))
.map((node)=>node.node);
const resultingGroupedData=[];
_映射(结果节点,(节点)=>{
push(_find(data,{ref:node.ref}));
});
返回结果组数据;
}
}
/**
*在更新发生后立即调用。
*@param prevProps
*/
componentDidUpdate(prevProps){
const{selectedmen,groupedData}=this.props;
如果(!\u isEqual(prevProps.selectedMenu,selectedMenu)){
常量filteredData=filterData(groupedData,selectedMenu);
const results=filteredData;
this.setState({results:results});
}
}
}
导出默认搜索;
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 };
/**
*供应商进口
*/
从“React”导入React;
常量defaultContextValue={
数据:{
//在此处设置初始数据形状
查询:“”,
},
集合:()=>{},
};
const{Provider,Consumer}=React.createContext(defaultContextValue);
类ContextProviderComponent扩展了React.Component{
构造函数(){
超级();
this.setData=this.setData.bind(this);
此.state={
…defaultContextValue,
set:this.setData,
};
}
setData(新数据){
this.setState((状态)=>({
数据:{
…状态数据,
…新数据,
},
}));
}
render(){
返回{this.props.children};
}
}
导出{默认为消费者,ContextProviderComponent};
我做错了什么


附言:如果你看到一些改进或无用的代码,我洗耳恭听

当它要求渲染函数是纯的时,它希望它不更新状态。它也不应该调用任何更新状态的东西

在search.jsx中,您将在render中调用this.handleSearch()。handleSearch()调用此.setState()。在通过上下文提供程序传入数据之前,您需要处理此搜索逻辑。(因此,将搜索处理逻辑移动到ContextProviderComponent中,并将搜索结果放入上下文中),或者您需要在渲染函数之外侦听上下文更改。答案给出了许多方法来做到这一点

至于代码质量,在我快速查看您的代码时,我没有看到任何明显的危险信号,干得好!你似乎具备了冷静反应的要领。

我找到了解决办法

@斯科特·贾米森关于这个问题的起源是正确的。他的回答帮助我重写了代码

Search.jsx

searchcontext.js

以下是我所做的:

以前的上下文组件不是我的。这是一个通用的样板文件。我不理解代码的意图。所以我查了一下,然后读了一遍。然后我简化了代码,将搜索逻辑导出到
search.jsx
组件之外,并简化了最后一个组件。

谢谢您的回答!我发布了我的新代码。现在,它就像一个符咒,我借此机会深入探讨了关于React上下文的Doc。很高兴你弄明白了!
/**
 * 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;
/**
 * 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;
  }
};
/**
 * 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('');