代码之家  ›  专栏  ›  技术社区  ›  tesicg

如何从外部更改反应组件?

  •  1
  • tesicg  · 技术社区  · 7 年前

    React组件可视为第三方组件,如下所示:

    import * as React from 'react';
    import classnames from 'classnames';
    import { extractCommonClassNames } from '../../utils';
    
    export const Tag = (props: React.ElementConfig): React$Node =>{
        const{
            classNames,
            props:
            {
                children,
                className,
                ...restProps
            },
        } = extractCommonClassNames(props);
    
        const combinedClassNames = classnames(
            'tag',
            className,
            ...classNames,
        );
    
        return (
            <span
              className={combinedClassNames}
              {...restProps}
            >
              {children}
              <i className="sbicon-times txt-gray" />
            </span>
        );
    };
    

    import React from 'react';
    import * as L from '@korus/leda';
    import type { KendoEvent } from '../../../types/general';
    
    type Props = {
      visible: boolean
    };
    
    type State = {
      dropDownSelectData: Array<string>,
      dropDownSelectFilter: string
    }
    
    export class ApplicationSearch extends React.Component<Props, State> {
      constructor(props) {
        super(props);
        this.state = {
          dropDownSelectData: ['Имя', 'Фамилия', 'Машина'],
          dropDownSelectFilter: '',
        };
        this.onDropDownSelectFilterChange = this.onDropDownSelectFilterChange.bind(this);
      }
    
      componentDidMount() {
        document.querySelector('.sbicon-times.txt-gray').classList.remove('txt-gray');
      }
    
      onDropDownSelectFilterChange(event: KendoEvent) {
        const data = this.state.dropDownSelectData;
        const filter = event.filter.value;
        this.setState({
          dropDownSelectData: this.filterDropDownSelectData(data, filter),
          dropDownSelectFilter: filter,
        });
      }
    
      // eslint-disable-next-line class-methods-use-this
      filterDropDownSelectData(data, filter) {
        // eslint-disable-next-line func-names
        return data.filter(element => element.toLowerCase().indexOf(filter.toLowerCase()) > -1);
      }
    
      render() {
        const {
          visible,
        } = this.props;
    
        const {
          dropDownSelectData,
          dropDownSelectFilter,
        } = this.state;
    
        return (
          <React.Fragment>
            {
              visible && (
                <React.Fragment>
                  <L.Block search active inner>
                    <L.Block inner>
                      <L.Block tags>
                        <L.Tag>
                          option 1
                        </L.Tag>
                        <L.Tag>
                          option 2
                        </L.Tag>
                        <L.Tag>
                          ...
                        </L.Tag>
                      </L.Block>
                    </L.Block>
                  </React.Fragment>
                )}
          </React.Fragment>
        );
      }
    }
    

    是否可以删除 "txt-gray"

    3 回复  |  直到 7 年前
        1
  •  2
  •   Bhojendra Rauniyar    7 年前

    从使用标记组件的位置删除类:

    componentDidMount() {
      document.querySelector('.sbicon-times.txt-gray').classList.remove('txt-gray')
    }
    

    .querySelector('span i.sbicon-times.txt-gray')
    

    根据你的评论,,

    我有多个带有“txt gray”的组件,但当我使用您的代码时,“txt gray”仅从第一个组件中删除。如何将其从所有组件中移除?

    我建议您使用代码删除使用标记组件的父组件中的类。并且还使用 querySelectorAll as in this post

        2
  •  1
  •   Estus Flask    7 年前

    重构

    一种干净的方法是修改组件,使其能够有条件地添加 txt-gray 通过道具:

    <i className={classnames('sbicon-times', { 'txt-gray': props.gray })} />
    

    使用 findDOMNode

    解决方法是直接在父组件中访问DOM:

    class TagWithoutGray extends React.Component {
      componentDidMount() {
        ReactDOM.findDOMNode(this).querySelector('i.sbicon-times.txt-gray')
        .classList.remove('txt-gray');
      }
    
      // unnecessary for this particular component
      componentDidUpdate = componentDidMount; 
    
      render() {
        return <Tag {...this.props}/>;
      }
    }
    

    芬多诺德 通常不鼓励直接DOM访问,因为直接DOM访问不是惯用的反应方式,它存在性能问题,并且与服务器端呈现不兼容。

    组件修补 cloneElement

    另一个解决方法是修补组件。自从 Tag 是函数组件,可以直接调用它来访问和修改其子级:

    const TagWithoutGray = props => {
      const span = Tag(props);
      const spanChildren = [...span.props.children];
      const i = spanChildren.pop();
    
      return React.cloneElement(span, {
        ...props,
        children: [
          ...spanChildren,
          React.cloneElement(i, {
            ...i.props,
            className: i.props.className.replace('txt-gray', '')
          })
        ]
      });
    }
    

    这被认为是一种黑客行为,因为包装器组件应该知道已修补的组件实现,如果实现发生更改,它可能会中断。

        3
  •  0
  •   Keilath    7 年前

    唯一的方法是更改标记组件

    import * as React from 'react';
    import classnames from 'classnames';
    import { extractCommonClassNames } from '../../utils';
    
    export const Tag = (props: React.ElementConfig): React$Node =>{
        const{
            classNames,
            props:
            {
                children,
                className,
                ...restProps
            },
        } = extractCommonClassNames(props);
    
        const combinedClassNames = classnames(
            'tag',
            className,
            ...classNames,
        );
    
        const grayClass = this.props.disableGray ? 'sbicon-times' : 'sbicon-times txt-gray';
    
        return (
            <span
              className={combinedClassNames}
              {...restProps}
            >
              {children}
              <i className={grayClass} />
            </span>
        );
    };
    

    现在,如果你通过 disableGray={true} 它将抑制灰色类,否则传递false或避免传递道具,它将使用灰色类。这是组件中的一个小更改,但它允许您不更改代码中使用此组件的所有点(并且您对灰色文本感到满意)