【问题标题】:Why isn't a state change affecting the display of options in a React Select component?为什么状态更改不会影响 React Select 组件中选项的显示?
【发布时间】:2021-06-13 07:45:49
【问题描述】:

我正在使用 react-select 作为下拉菜单。我在搜索时使用异步调用来获取选项,但我没有使用 AsyncSelect 组件,因为我只希望它在获得焦点后获取(一页上的很多内容会导致流量过多)。

因此,我使用基本的 Select 组件来执行此操作:this.state.options 在获取时更新并传递到组件“options”属性中。 问题是当 this.state.options 更改时,选项列表显示变为空。我已在渲染时将 this.state.options 打印到控制台,以确认当搜索输入更改时它确实更改为正确填充的列表,但组件显示“无选项”。

这是 this.state.options 的示例内容。这是正确的行为。

Array [ {…}, {…} ]
​
0: Object { value: {…}, label: "Calcite Crystal Formation" }
​
1: Object { value: {…}, label: "Lithium Crystal Formation" }

如果我取消聚焦然后重新聚焦组件,选项列表会更新并正确显示新选项。但否则它会更改为显示“无选项”,这不反映 this.state.options。如何正确更新选项列表?还是我做错了?

这里是使用 Select 组件的组件(相关部分):

import React, { Component }                 from 'react'
import Select, { components }               from 'react-select'
import { API_post }                         from '../../util_components/API'

class RelationalField extends Component{
    constructor(props) {
        super(props);
        this.state = this.resetState()
    }
    resetState(){
        return {
            options: [],
            input: null
        }
    }
    render(){
        console.log(this.state.options)
        let curr_value = undefined
        if(this.props.curr_value) curr_value = {label:(this.props.curr_value.title || this.props.curr_value.username), value:this.props.curr_value}
        return (
          <Select
            placeholder={this.state.input || ''}
            options={this.state.options}
            input={this.state.input}
            onFocus={() => this.loadOptions(this.state.input)}
            onInputChange={this.loadOptions.bind(this)}
            value={curr_value}
            getOptionLabel={this.renderOption.bind(this)}
            onChange={this.onSingleSelect.bind(this)}
          />
    }
    onSingleSelect(selection){
        if(selection && selection.value && selection.label) selection = selection.value
        this.props.handleChange({target:{name: this.props.fieldRealName, value: selection}})
    }
    loadOptions(query){
        if(query === this.state.input && this.state.options.length !== 0) return
        if(query == '') return
        if(query == null) query = ''
        var filtering = {
            start: 0,
            end: 25,
            object_types: [this.state.target_model].flat(),
            filter: [query]
        }
        if(this.props.known_alias_list){
            API_post('global-search', filtering, function(response){
                this.setState({
                    input: query,
                    options: response.data.objects.map(x=> {if(x.username){return {value: x, label:x.username}} 
                                                            else         return {value: x, label:x.title}})
                }, )
            }.bind(this), this)
        }
        
    }
    renderOption(option){
        if(!option || !this.props.known_alias_list) return null
        return (
            <table className='highlight-on-hover' style={{width: '100%'}}><tbody><tr>
               <td>{option.label}
               {Object.keys(this.props.known_alias_list).includes(option.value.id) && ' ('+this.props.known_alias_list[option.value.id]+')'}</td> 
               {option.value.image &&
                    <td><ObjectImage picture={option.value.image} 
                    style={option.value.username
                        ? {height: '25px', width: '25px', float: 'right', borderRadius: '50%'}
                        : {height: '25px', width: '25px', float: 'right'}}/></td>
                }
            </tr></tbody></table>
        )
    }
}

export default RelationalField

【问题讨论】:

  • 仅供参考,我试图解析这个,设置一个代码框来玩,试图窥视源代码以查看 Select 自身何时重新渲染,但没有走得太远。如果您没有得到太多答案,我建议您进一步简化示例。您甚至可能会在这样做时发现问题。如果 this.state 在您的 render() 调用中显示正确的信息,我不禁认为 react-select 组件没有重新渲染,这就是查看的地方。您还可以尝试使用 react 开发工具查看 react-select 组件,以查看 Select 具有哪些道具。 GL!
  • 谢谢!使用 react 开发工具查看可能的道具的建议帮助我找到了解决方案!
  • 很高兴听到......所以让它重新渲染可能是一些技巧?如果您也有时间,您可以回答自己的问题并接受它以供将来查看
  • 是的!当我收到您的回复时,我正在打字:) 问题是找到合适的道具来为每个选项传递自定义渲染函数。

标签: reactjs react-select


【解决方案1】:

经过反复试验,发现问题是因为我使用自定义方法来呈现每个选项。

将此方法传递给“getOptionLabel”道具仅适用于组件的第一次渲染,当时我正在关注组件。相反,这个函数应该作为“Option”组件函数传递给“components”道具:

<Select
isSearchable
isClearable
placeholder={this.state.input || ''}
menuPlacement='auto'
options={option_list}
input={this.state.input}
onFocus={() => this.loadOptions(this.state.input)}
onInputChange={this.loadOptions.bind(this)}
value={curr_value}
// getOptionLabel={this.renderOption.bind(this)} << this is incorrect
classNamePrefix={'smartlab-select'}
onChange={this.onSingleSelect.bind(this)}
components={{
             SingleValue: this.BubbleLinkLabelSingle.bind(this), 
             animatedComponents: animatedComponents,
             Option: this.OptionDisplay.bind(this)
}}
/>

...

// previously known as "renderOption"
OptionDisplay = (option) => {
   if(!option || !this.props.known_alias_list) return null
   return (
      <table className='highlight-on-hover' {...option.innerProps}>
      <tbody><tr>
               <td>{option.label}</td> 
               {option.value.image &&
               <td><ObjectImage picture={option.value.image}/></td>
               }
       </tr></tbody></table>
    )
}

【讨论】:

    【解决方案2】:

    我相信您想要的是 PureComponent,它允许在初始渲染后根据状态更改重新渲染。

    这里有一些关于它的信息:https://reactjs.org/docs/react-api.html#reactpurecomponent

    【讨论】:

    • 如果您的意思是将此 RelationalField 组件的父类更改为“PureComponent”而不是“Component”,我刚刚尝试过,并且发生了相同的行为。
    • 如果数据被设置为您根据console.log确认的状态,那么这纯粹是一个渲染问题。我会尝试将 Select 组件更改为 PureComponent,或者如果它是功能性的,则将选项道具作为依赖项传递给 useEffect 挂钩。
    • 我现在已经尝试了这两个选项,但似乎都没有改变上述行为。我认为这个问题是特定于 react-select 的,我可能会丢失一些我在 react-select 文档中找不到的道具。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多