简体   繁体   English

使用先前状态选项的 Material UI 自动完成

[英]Material UI Autocomplete using previous state options

I'm trying to suggest data using the autocomplete component based on 2 queries that fetch data from GraphQL.我正在尝试使用基于从 GraphQL 获取数据的 2 个查询的自动完成组件来建议数据。


    const handleSearchChange = (evt, newInputValue) => {
      const {
        agentsEmail,
        prefix,
        appsName,
        role,
        fromDate,
        toDate,
      } = this.props;
      console.log("handle Search Change")
      this.setState({ userInput: evt.target.value });
      if (newInputValue.length > 0) {
        this.setState({ open: true });
        setTimeout(() => {  this.prepareFilterData(appsName, agentsEmail, prefix, role, fromDate, toDate); }, 500);
      } else {
        this.setState({ open: false });
      }
    }

    const handleSelection = (evt, evtSelection, reason) => {
      console.log(reason, "REASON handle Selection")

      this.setState({ selection: evtSelection });

      /* map over selection and for each element push to listings the element.id
      to build the list of ids to be used by the seearch button handle event */
      this.state.selection.map( (selection) => listings.push(selection.id))
      console.log(this.state.selection, "SELECTION")
    }


    <Autocomplete
            id="listings-filter"
            multiple
            open={this.state.open}
            onOpen={handleOpen}
            onClose={() => this.setState({ open: false })}
            options={filterList}
            limitTags={4}
            groupBy={(option) => option.key}
            disableCloseOnSelect
            onChange={handleSelection}
            onInputChange={handleSearchChange}
            getOptionLabel={(option) => option.value}
            renderOption={(option, { selected }) => (
             <React.Fragment>
               <Checkbox
                 icon={icon}
                 checkedIcon={checkedIcon}
                 style={{ marginRight: 8 }}
                 checked={selected}
               />
             {option.value}
             </React.Fragment>
            )}
            renderInput={(params) => (
             <TextField {...params} label="Search listings by" placeholder="Address, MLS" />
            )}
          />

I'm using a class component, and the options are a list I formatted to allow them to be grouped with the Autocomplete component, but it is always using a previous state of the options.我正在使用类组件,选项是我格式化的列表,以允许它们与自动完成组件分组,但它始终使用选项的先前状态。 for example: I type ca on the input and it fetches 100 values, but it uses that 100 values when I blur the input which clears the input and it loads the 100 fields.例如:我在输入上键入ca并获取 100 个值,但是当我模糊清除输入并加载 100 个字段的输入时,它使用这 100 个值。 then when I type something else the empty options got loaded.然后当我输入其他内容时,空选项被加载。 I always need to do +1 change event to got the actual options list, I tried setting to false the clearOnBlur property which didn't solve the issue because since the change event is not fired when blurring the input it never update the state (+1).我总是需要做 +1 更改事件来获取实际的选项列表,我尝试将clearOnBlur属性设置为 false 没有解决问题,因为由于在模糊输入时未触发更改事件,因此它永远不会更新状态(+ 1)。 Any idea what could be causing this?知道是什么原因造成的吗? Thanks in advice Here a animated example of my issue:感谢建议 这是我的问题的动画示例: 在此处输入图片说明

EDIT: This behavior also happen when deleting the selected options or selecting them, if I select one of the options the change event reflects an empty list, when I select a second one it reflect just the first I selected.编辑:删除所选选项或选择它们时也会发生这种行为,如果我选择其中一个选项,则更改事件反映一个空列表,当我选择第二个选项时,它仅反映我选择的第一个。

This is the function I use to format and update the filterList I fetch the data with the fetchMls and fetchAddresses then using the mergeFilterData I update the filter list used on the options property这是我用来格式化和更新filterList的函数我使用 fetchMls 和 fetchAddresses 获取数据然后使用mergeFilterData我更新选项属性上使用的过滤器列表

  prepareFilterData = async (appsName, agentsEmail, prefix, role, fromDate, toDate) => {
    await this.fetchMls(appsName, agentsEmail, prefix, role, fromDate, toDate);
    await this.fetchAddresses(appsName, agentsEmail, prefix, role, fromDate, toDate);
    this.setState({
      filterList: mergeFilterData(this.state.fetchedAddresses, this.state.fetchedMls, [])
    });
    console.log(this.state.filterList, "FINAL DATA")
    /* this.setState({
      filteredList: handleListChange(userInput, listingsList, 0.5),
    }); */
  }

EDIT2: Here is one of the functions I use to fetch the data, when the data is fetched is formated and saved on a state to be used. EDIT2:这是我用来获取数据的函数之一,当获取数据时,它被格式化并保存在要使用的状态上。

  fetchMls = async (appsName, agentsEmail, prefix, role, fromDate, toDate) => {
    const enumerationAppName = appsName.map((appName) => appName.enumeration);
    const listAgents = agentsEmail.map((agent) => agent.name || agent);
    console.log(this.state.userInput, "USER INPUT ON FETCH MLS")
    const query = {
      query: GET_LISTINGS_BY_MLS_PREFIX_QUERY,
      variables: {
        appsName: enumerationAppName,
        agentsEmail: listAgents,
        prefix,
        fromDate: formatDate(fromDate),
        toDate: formatDate(toDate),
        mlsPrefix: this.state.userInput || "1",
      },
    };

    applicationClient
      .query(query)
      .then((response) => {
        if (response) {
          if (!isEmpty(response.data.getListingsByMlsPrefix.data)) {
            const result = response.data.getListingsByMlsPrefix.data.map(
              (listing) => listing
            );
            const formatedMls = formatMls(result);
            this.setState({ fetchedMls: formatedMls });
          }
        }
      })
      .catch((err) => {
        this.setState({ fetchedMls: [] });
      });
  };

If you need to process data after state updates, the best way is on callback function:如果您需要在状态更新后处理数据,最好的方法是使用回调函数:

 const handleSearchChange = (evt, newInputValue) => {
      const {
        agentsEmail,
        prefix,
        appsName,
        role,
        fromDate,
        toDate,
      } = this.props;
      console.log("handle Search Change")
      this.setState({ 
        userInput: newInputValue,
        open: newInputValue > 0
      });
      if (newInputValue.length > 0) {
         setTimeout(() => {  this.prepareFilterData(appsName, agentsEmail,   prefix, role, fromDate, toDate); }, 500);
      }
      
    }

const handleSelection = (evt, evtSelection, reason) => {
  console.log(reason, "REASON handle Selection")
  this.setState({ selection: evtSelection }, ()=> {
      this.state.selection.map( (selection) => listings.push(selection.id))
      console.log(this.state.selection, "SELECTION")
  });

  /* map over selection and for each element push to listings the element.id
  to build the list of ids to be used by the seearch button handle event */

}

I don't know what is in this.fetchMls and this.fetchAddresses functions, but I recommend you to get the data directly, something like this:我不知道 this.fetchMls 和 this.fetchAddresses 函数中是什么,但我建议您直接获取数据,如下所示:

 prepareFilterData = async (appsName, agentsEmail, prefix, role, fromDate, toDate) => {
        const fetchedAddresses = await this.fetchMls(appsName, agentsEmail, prefix, role, fromDate, toDate);
        const fetchedMls = await this.fetchAddresses(appsName, agentsEmail, prefix, role, fromDate, toDate);
        this.setState({
          filterList: mergeFilterData(fetchedAddresses, fetchedMls, [])
        }, ()=> console.log(this.state.filterList, "FINAL DATA"));
       
      }

I hope this help you ;)我希望这对你有帮助;)

该问题与材料 UI 组件无关,问题与我正在获取的数据有关,因为我正在获取 3 个不同的查询,我遇到了竞争条件错误,所以我通过使用 Promises.all 解决所有承诺来解决它() 如果对任何人有用 ;)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM