React - 更改单个跨度 class 的背景不起作用

React - changing the background of a single span class not working

我是 React 的新手,所以如果问题或我试图实现的事情很奇怪,我深表歉意(请告诉我是否有更好/更合乎逻辑的方法来做到这一点)。

我在我的 React 应用程序中使用 List Fabric React 组件,它基于可在此处找到的 ListGridExample 组件: https://developer.microsoft.com/en-us/fabric#/components/list

我已经设置好了,但我似乎无法完成以下操作:

当点击 List 组件中的 span class(实际上是一个项目)时,我想将其更改为 background color,为此我已按照说明进行操作以下 post: https://forum.freecodecamp.org/t/react-js-i-need-a-button-color-to-change-onclick-but-cannot-determine-how-to-properly-set-and-change-state-for-that-component/45168

这是一个相当简单的示例,但这会将我所有的 grid cells / span classes 更改为蓝色,而不仅仅是单击的那个。有没有一种方法可以让点击的范围 class 改变它的背景?

初始状态:

点击一个span后的状态class(错误):

实现代码(省略一些不必要的代码):

class UrenBoekenGrid extends React.Component {

    constructor(props) {
      super(props);

      this.state = {
        bgColor: 'red'
     }

    }

    render() {
      return (
        <FocusZone>
          <List

            items={[
                {
                key: '#test1',
                name: 'test1',
                },
                {
                name: 'test2',
                key: '#test2',
                },
                {
                name: 'test3',
                key: '#test3',
                },
                {
                name: 'test4',
                key: '#test4',
                },

                ..... up to 32 items

            ]}

            onRenderCell={this._onRenderCell}

          />
        </FocusZone>
      );
    }


    changeColor(item){
        this.setState({bgColor: 'blue'});

        console.log('clicked item == ' + item.name)

      }



    _onRenderCell = (item, index) => {

        return (
          <div
            className="ms-ListGridExample-tile"
            data-is-focusable={true}
            style={{
              width: 100 / this._columnCount + '%',
              height: this._rowHeight * 1.5,
              float: 'left'
            }}
          >
            <div className="ms-ListGridExample-sizer">
              <div className="msListGridExample-padder">

                {/* The span class with the click event: */}
                <span className="ms-ListGridExample-label" onClick={this.changeColor.bind(this, item)} style={{backgroundColor:this.state.bgColor}}>{`item ${index}`}</span>
                <span className="urenboeken-bottom"></span>

              </div>
            </div>
          </div>
        );
    };


}

我现在已将 click event 附加到 span class 本身,但我认为将 click event 放在 item(s)(数组)上更符合逻辑本身,但是我也找不到实现此目标的方法。

----更新----

@peetya 的回答似乎是可行的方法,因为@Mario Santini 的回答只是更新一个单元格,如果单击另一个单元格,则前一个 returns 恢复正常并失去它的颜色。

所以我所做的是将 items array 添加到 state 并将 bgColor 属性 添加到它们:

this.state = {
        items: [
            {
                key: '#test1',
                name: 'test1',
                bgColor: 'blue',
            },
            {
                name: 'test2',
                key: '#test2',   
                bgColor: 'blue',    
            },
            {
                name: 'test3',
                key: '#test3',
                bgColor: 'blue',    
            },
            {
                name: 'test4',
                key: '#test4',
                bgColor: 'blue',    
            },
        ],
     }

现在,在我的 List 渲染中,我已将项目设置为 state items 数组,并在 _onRenderCell 函数中添加了 onClick 事件:

render() {
      return (
        <FocusZone>
          <List

            items={this.state.items}

            getItemCountForPage={this._getItemCountForPage}
            getPageHeight={this._getPageHeight}
            renderedWindowsAhead={4}
            onRenderCell={this._onRenderCell}

          />
        </FocusZone>
      );
    }


_onRenderCell = (item, index) => {

        return (
          <div
            className="ms-ListGridExample-tile"
            data-is-focusable={true}
            style={{
              width: 100 / this._columnCount + '%',
              height: this._rowHeight * 1.5,
              float: 'left'
            }}
          >
            <div className="ms-ListGridExample-sizer">
              <div className="msListGridExample-padder">

                <span className="ms-ListGridExample-label" 
                     onClick={this.onClick(item.name)} 
                     style={{backgroundColor: item.bgColor}}
                >
                    {`item ${index}`}
                </span>

                <span className="urenboeken-bottom"></span>



              </div>
            </div>
          </div>
        );
    };

问题是我无法在 _onRenderCell 函数中添加 onClick event,因为这会出现以下错误:

我想保留 Fabric List component,因为它还具有渲染/调整屏幕大小的功能,完全删除列表组件并用 @peetya 建议的作品替换它:

render() {
        <div>
            {this.state.items.map(item => (
                <div onClick={() => this.onClick(item.name)} style={{backgroundColor: item.bgColor}}>
                    {item.name}
                </div>
            ))}
        </div>
    }

但这也会删除 List 组件功能及其 responsive 功能。

所以我最后的想法是用整个 onClick div 替换 Listitems 并删除 _onRenderCell 函数本身,但这会使页面空白(完全看不到单元格..):

  render() {
      return (
        <FocusZone>
          <List

            items={this.state.items.map(item => (
                <div onClick={() => this.onClick(item.name)} style={{backgroundColor: item.bgColor}}>
                    {item.name}
                </div>
            ))}

            getItemCountForPage={this._getItemCountForPage}
            getPageHeight={this._getPageHeight}
            renderedWindowsAhead={4}
           // onRenderCell={this._onRenderCell}

          />
        </FocusZone>
      );
    }

我认为也许 css ms-classes / div 也应该在那里,因为它们具有 height/width 属性但添加它们(完全一样在 _onRenderCell 函数中)没有任何区别,页面仍然是空白。

实际上,您正在更改所有跨度元素的颜色,因为您为每个跨度设置了状态变量的样式 bgColor

相反,您应该保存点击的项目,并据此决定颜色:

this.state = {
    bgColor: 'red',
    clickedColor: 'blue
}

在构造函数中。

然后在点击处理程序中:

changeColor(item){
    this.setState({selected: item.name});

    console.log('clicked item == ' + item.name)
}

所以在渲染器中(我只是把相关部分):

<span ... style={{backgroundColor: (item.name === this.state.selected ? this.state.clickedColor : this.state.bgColor)}}>{`item ${index}`}</span>

问题是您将背景颜色存储在网格状态中并将此状态分配给网格的每个元素,因此如果您更新状态,它将影响每个元素。最好的方法是,如果您为 Grid 元素创建一个单独的组件并将它们自己的状态存储在其中,或者如果您只想使用一个状态,则将 items 数组存储在该状态内并添加一个新的 bgColor 属性,因此如果您只想更改一项的背景颜色,则需要为 items 数组的特定对象调用 setEstate。

这是一个小例子(我没有测试过):

class UrenBoekenGrid extends React.Component {
    constructor(props) {
        super(props);

        this.state = {
            items: [
                {
                    key: '#test1',
                    name: 'test1',
                    bgColor: 'blue',
                },
            ],
        };
    }

    onClick(name) {
        this.setState(prevState => ({
            items: prevState.items.map(item => {
                if (item.name === name) {
                    item.bgColor = 'red';
                }

                return item;
            })
        }))
    }

    render() {
        <div>
            {this.state.items.map(item => (
                <div onClick={() => this.onClick(item.name)} style={{backgroundColor: item.bgColor}}>
                    {item.name}
                </div>
            ))}
        </div>
    }
}