Остановить распространение в обработчике React onclick - PullRequest
0 голосов
/ 15 февраля 2019

У меня проблема с распространением в реакции.Мне нравится этот метод, который отображает div-теги с p-тегами внутри:

private renderTags(tag: Tags, index: number) {
    return <div>
        <div  onClick={(e) => { e.stopPropagation(); this.collectTags(tag); }}>
            <p className={styles.tag}># {tag.title} <i className="ms-Icon ms-Icon--CirclePlus"></i></p>
        </div>
    </div>

}

, этот метод вызывается из рендера следующим образом:

<div className={styles.tagsContainer}>
                {this.state.items.slice(0, 12).map((w, index) => this.renderTags(w, index))}
            </div>

Как вы видите вызовы метода renderTagsдля каждого элемента в массиве.

идея первого метода заключается в том, что когда пользователь щелкает один из элементов, этот элемент отправляется в массив, проблема заключается в том, что когда я щелкаю один из этих элементов, все элементы отправляются в массив,Я проверил, добавив имя класса к элементу, по которому щелкнули, просто для проверки причины, и я вижу, что такое же поведение возникает, когда я щелкаю по одному из элементов, все элементы получают имя класса.

как я могу остановить это распространение ?.кстати, это метод, который прослушивает щелчок и помещает выбранный элемент в массив:

 private collectTags(newTag: Tags): any {
    //this.setState({ savingSettings: true, tagActive: true });

    let selectedTags: Tags[] = this.state.selectedTags;

    selectedTags.push(newTag);
    this.setState({
        selectedTags: selectedTags,
        hideSaveButton: false
    });


    return selectedTags;

}

ОБНОВЛЕНИЕ

Лучше я выложу весь код:

    import * as React from 'react';
import { CacheManager } from "../../common/CacheManager";
import { ITagsDataProvider } from "../../interfaces/ITagsDataProvider";
import Tags from "./Tags";
import styles from './TagsContainer.module.scss';

import { Dialog, DialogFooter } from 'office-ui-fabric-react/lib/Dialog';
import { DefaultButton } from 'office-ui-fabric-react/lib/Button';

export interface ITagsContainerProps {
    provider: ITagsDataProvider;
}

export interface ITagsContainerState {
    items: Tags[];
    allTags: Tags[];
    selectedTags: Tags[];
    savingSettings: boolean;
    currentTagsIndex: number;
    activeTile: number;
    hideDialog: boolean;
    hideSaveButton: boolean;

}

export default class TagsContainer extends React.Component<ITagsContainerProps, ITagsContainerState> {
    private readonly cacheKey = "TagsLinks";

    constructor(props: ITagsContainerProps) {
        super(props);
        this.state = {
            items: [],
            allTags: [],
            selectedTags: [],
            savingSettings: false,
            currentTagsIndex: -1,
            activeTile: -1,
            hideDialog: true,
            hideSaveButton: true
        }
    }

    public componentDidMount(): void {
        var cacheManager = new CacheManager();
        var cachedValue = cacheManager.get(this.cacheKey);

        //If there are cached values update the state
        if (cachedValue) {
            this.setState({
                items: cachedValue,
                allTags: [],
                savingSettings: false,
                currentTagsIndex: -1
            });

            return;
        }

        this.props.provider.getAllTags().then((tags) => {
            if (tags != null) {
                cacheManager.set(this.cacheKey, tags);
            }

            this.setState({
                items: tags,
                allTags: [],
            });
        });



    }



    private renderTags(tag: Tags, index: number) {
        return <div>
            <div  onClick={(e) => this.onTagClick(tag, e)}>
                <p className={styles.tag}># {tag.title} <i className="ms-Icon ms-Icon--CirclePlus"></i></p>
            </div>
        </div>

    }

    private onTagClick(tag: Tags, e: React.MouseEvent<HTMLDivElement>) {
        e.stopPropagation();
        this.collectTags(tag);
    }

    private collectTags(newTag: Tags): any {

        this.setState({
            selectedTags: {
                ...this.state.selectedTags,
                newTag
            },
            hideSaveButton: false
        });


    }


    private saveSettings(): void {

         let sTags = this.state.selectedTags;

        this.setState({
            items: sTags
        });
        console.log('SELECTED TAG ' + this.state.items);
       var cacheManager = new CacheManager();
        cacheManager.set(this.cacheKey, sTags);

        this.props.provider.saveSettingsData(sTags).then(() => {
            this.setState({
                savingSettings: false
            });
        });

    }


    // Render the tags in the dialog box
    private onRenderDialog = (tag: Tags, index: number): JSX.Element => {
        return (
            <div className={styles.tag} onClick={(e) => { e.stopPropagation(); this.collectTags(tag); }}>
                <span># {tag.title} <i className="ms-Icon ms-Icon--CirclePlus"></i></span>
            </div>
        )
    }

    public render(): JSX.Element {
        return <div className={styles.tagCloud}>
            <div>
                <h1>What are you interested in?</h1>
                <p>We'll show you more stories from the topics you pick below</p>
            </div>
            <div>
                <div className={styles.tagsContainer}>
                    {this.state.items.slice(0, 12).map((t, index) => this.renderTags(t, index))}
                </div>
                <div>
                    <a className={styles.allItemsLink} href="#" onClick={this._showDialog}>View all topcis</a>
                </div>
                <div>

                   { this.state.hideSaveButton === false ? <DefaultButton 
                        text="Done"
                        style={{ backgroundColor: '#ff0033', color: '#ffffff' }}
                        onClick={(e) =>{e.stopPropagation(); this.saveSettings()}}
                    /> : null} 

                </div>
            </div>

            <Dialog
                hidden={this.state.hideDialog}
                onDismiss={this._closeDialog}
                containerClassName={'ms-dialogMainOverride ' + styles.textDialog}
                modalProps={{
                    isBlocking: true,
                }}>

                <div className={styles.tagsDialogContainer}>
                    {this.state.allTags.map((t, index) => this.onRenderDialog(t, index))}
                </div>
                <DialogFooter>
                    <DefaultButton
                        style={{ backgroundColor: '#ff0033', color: '#ffffff' }}
                        onClick={this._closeDialog} 
                        text="Done"
                    />
                </DialogFooter>
            </Dialog>
        </div>
    }

    private _showDialog = (): void => {
        this.setState({ hideDialog: false });

        this.props.provider.getAllTags().then((items) => {
            this.setState({ allTags: items });
        })
    };

    private _closeDialog = (): void => {
        this.setState({ hideDialog: true });

    }
}

С уважением, Американо

1 Ответ

0 голосов
/ 15 февраля 2019

Прежде всего вам нужно создать отдельный метод для обработки событий, например onTagClick.

private renderTags(tag: Tags, index: number) {
    return <div>
        <div onClick={e => this.onTagClick(e, tag)}>
            <p className={styles.tag}># {tag.title} 
                <i className="ms-Icon ms-Icon--CirclePlus"></i>
            </p>
        </div>
    </div>

}

private onTagClick(tag: Tags, e: React.MouseEvent<HTMLElement>) {
    e.stopPropagation(); 
    this.collectTags(tag);
}

Еще одна проблема - вы изменяете состояние напрямую, что не разрешено в React.

// Here you creating the link to array named `selectedTags`.
let selectedTags: Tags[] = this.state.selectedTags;

// and here you mutating your state directly
selectedTags.push(newTag);

Просто скопируйте ваш массив перед добавлением нового элемента или используйте оператор распространения.

private collectTags(newTag: Tags): any {
    this.setState({
        selectedTags: {
            ...this.state.selectedTags,
            newTag
        },
        hideSaveButton: false
    });
}

Также не забудьте связать контекст с методом collectTags в конструкторе.

constructor(props) {
    super(props);
    ...some code if you have...
    this.collectTags = this.collectTags.bind(this);
}

Надеюсь, это помогло.

...