Идиоматический способ отправки действия над подкомпонентом в реагирующем редуксе без передачи реквизитов на всем протяжении

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

--------------------------------
| title 1         |----------| | 
| description 1   | button 1 | |
| desc... cont.   |----------| |
|------------------------------|
| title 2         |----------| | 
| description 2   | button 2 | |
| desc2... cont.  |----------| |
|------------------------------|
| title 3         |----------| | 
| description 3   | button 3 | |
| desc3... cont.  |----------| |
|------------------------------|

Это представляет собой список Items. Каждый Item (3 показаны на диаграмме) имеет title и description. Когда я нажимаю кнопку, я хочу выполнить какое-то действие для этого Item, например, отобразить окно предупреждения с заголовком Item's.

Мне удалось создать рабочий пример на основе учебника по Redux. В итоге я получил 1 контейнерный (интеллектуальный) компонент с именем ItemsContainer.tsx и два компонента Presentation (глупые) с именами ItemList.tsx (список) и Item.tsx (отдельный элемент). Иерархически это выглядит так...

App
-- ItemsContainer
---- ItemList
------ Item
------ Item

Однако, как и в случае с Redux Tutorial, для этого требовалось, чтобы я передал функцию onClick через каждый из компонентов презентации через свойства. Если бы у меня было гораздо более глубокое вложение, это могло бы стать обременительным, поэтому я пытаюсь найти другой способ.

Теперь у меня есть два компонента-контейнера ItemListContainer.tsx, ItemContainer.tsx и два компонента представления ItemList.tsx и Item.tsx. Однако всякий раз, когда я нажимаю кнопку, в окне предупреждения просто отображается [Object object]. Я считаю, что происходит то, что я на самом деле получаю событие нажатия кнопки, а не Item.id, но я не уверен, куда идти отсюда, чтобы убедиться, что для onClick назначена правильная функция. Иерархически это выглядит так...

App
-- ItemListContainer
---- ItemList
------ ItemContainer
-------- Item
-------- Item

Код выглядит следующим образом...

// app.tsx
import * as React from 'react';
import { ItemListContainer } from '../addItem/ItemListContainer';

export const App = () => {
    return <div><ItemListContainer/></div>;
};
// itemListContainer.tsx
import { ItemList } from './itemList';
import { connect } from 'react-redux';


function mapStateToProps(state: any): any {
    return {
        items: state.items
    }
}

export const ItemListContainer = connect(mapStateToProps, null)(ItemList);
// itemList.tsx
import * as React from 'react';
import { IItems, IItemSummary } from '../../data/Items/models/Item';
import { ItemContainer } from './ItemContainer';

export const ItemList = (props: IItems) => {

    let divStyle = {
            position: 'block',
            border: 'solid #aeb0b5 1px',
            overflowY: 'auto',
            overflowX: 'hidden',
            width: 650,
            height: 300
    };

    return (
        <div style={divStyle}>
            {
                props.items.map(function (item: IItemSummary) {
                    return <ItemContainer {...item} />;
                })
            }
        </div>
    );
};
// itemContainer.tsx
import { Item } from './Item';
import { IItems } from '../../data/Items/models/Item';
import { removeItem } from "../../data/Items/actions/initDashboardItems"
import { connect } from 'react-redux';


function mapStateToProps(state: any): any {
    return {
        items: state.items
    };
}


const mapDispatchToProps = (dispatch: any): any => {
    return {
        onClick: (id: any) => {
            alert(id);
        }
    };
};

export const ItemContainer = connect(
    mapStateToProps,
    mapDispatchToProps
)(Item);
// item.tsx
import * as React from 'react';
import { IItemSummary } from '../../data/items/models/item';

export const item = (props: IItemSummary) => {

    let outerDiv = {
            position: 'relative',
            borderBottom: 'solid #aeb0b5 1px',
            width: '650px'
        };

        let textDiv = {
            position: 'relative',
            width: '500px',
            padding: 5
        };

        let buttonDiv = {
            position: 'absolute',
            top: '5px',
            right: '10px',
            padding: 5
        };

    return (
        <div style={outerDiv}>
            <div style={textDiv}><strong>{props.title}</strong></div>
            <div style={textDiv}>{props.description}</div>
            <div style={buttonDiv}><button onClick={props.onClick}>Add Chart</button></div>
        </div>
    );
};

Хотя мне в конечном итоге нужно решить, как связать правильную функцию с onclick с помощью React и Redux, я также хочу знать, каков идиоматический способ React Redux для структурирования этого кода для пользовательского интерфейса, описанного в начале этого поста?


person Ryan Taylor    schedule 02.06.2016    source источник


Ответы (2)


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

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

person basarat    schedule 02.06.2016

Решение проблемы с неправильной проводкой onClick состояло в том, чтобы изменить файл item.tsx следующим образом...

// item.tsx
import * as React from 'react';
import { IItemSummary } from '../../data/items/models/item';

export const item = (props: IItemSummary) => {

    const clickHandler = () => props.onClick(props.title);

    // style stuff omitted for clarity

    return (
        <div style={outerDiv}>
            <div style={textDiv}><strong>{props.title}</strong></div>
            <div style={textDiv}>{props.description}</div>
            <div style={buttonDiv}><button onClick={clickHandler}>Add Chart</button></div>
        </div>
    );
};

Была введена явная функция clickHandler, чтобы props.title можно было передать в метод props.onClick.

Я до сих пор не уверен, является ли это идиоматической реакцией-редукцией, и могу обновить этот ответ, если будет найден более подходящий метод.

(Спасибо acemarke и другим участникам канала сообщества Redux на discordapp.com за их помощь)

person Ryan Taylor    schedule 02.06.2016