Реагировать — отключить строку при нажатии кнопки

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

Код, который я ранее написал, просто отключает кнопки для каждой строки. Что было бы не правильно. Для некоторого контекста см. скриншот приложения, которое я пишу:

введите здесь описание изображения

Когда пользователь нажимает Generate Journey для определенной строки, мне нужно отключить кнопку «Создать путешествие» для этой конкретной строки, чтобы они не делали это снова (что вызовет проблемы на стороне сервера).

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

Итак, вот мой код:

Функция рендеринга на скриншоте выше выглядит следующим образом:

 render() {
    return (
        <div className="polls-container">
            <div className="dashboard-title" style={{paddingTop: "2%", marginLeft: "-50px"}}>
                <h2>Dashboard</h2>
            </div>
            {
                !this.state.loading && this.state.results.length > 0 ? (
                    <RouteTable buttonDisabled ={this.state.emulateButtonDisabled} results={this.state.results} generateJourney={this.generateJourney} startEmulation={this.getJourneyEmulations}/>
                ) : null
            }
            {
                !this.state.isLoading && this.state.results.length === 0 ? (
                    <div className="no-polls-found">
                        <span>No Active Journey Generations</span>
                    </div>    
                ): null
            }
            {
                this.state.isLoading ? 
                <LoadingIndicator />: null                     
            }
        </div>
    );
}
}  

В основном это относится к компоненту Route Table, который отображает таблицу, показанную на скриншоте. Обратите внимание, как я передаю results={this.state.results} generateJourney={this.generateJourney} startEmulation={this.getJourneyEmulations} в качестве реквизита.

Свойство результатов - это просто извлеченные данные таблицы. Код для функции «generateJourney» выглядит следующим образом (выполняется при нажатии кнопки Generate Journey):

 generateJourney = (customerId, startDate, endDate, linkedCustomers, lat, lng) => {
   let confirmGenerateJourney = window.confirm('Are you sure you want to start this Journey Generation?')
    if (confirmGenerateJourney) {
        fetch('http://10.10.52.149:8081/generate-journeys', {
            method: 'POST',
            mode:'cors',
            headers: {
                'Content-Type': 'application/json',
                'Access-Control-Allow-Origin': '*',
            },
            body: JSON.stringify( {
                customerId: customerId,
                startDate: startDate,
                endDate: endDate,
                serviceIds: linkedCustomers,
                homeLat: lat,
                homeLng: lng
            })
        }).then(response => response.json())
                .catch(err => console.log(err))

        notification.success({
            message: 'Kinesis Fake Telemetry',
            description: "Journey has Started being Generated",
        });

        fetch('http://localhost:8080/api/routeGen/updateCustomerStatus', {
            method: 'PUT',
            mode:'cors',
            headers: {
                'Content-Type': 'application/json',
                'Access-Control-Allow-Origin': '*',
            },
            body: JSON.stringify( {
                customerId: customerId,
                status: 1
            })
        }).then(response => response.json())
            .catch(err => console.log(err))

        window.location.reload();
    }
}

Ничего особенного, просто вызов API для данных POST или PUT. После этого, вот код для startEmulation={this.getJourneyEmulations}, который нажимается при нажатии кнопки Emulate. Это в основном проверяет, что путешествие было сгенерировано, прежде чем мы сможем его эмулировать. (ждет статус готово)

Мой класс RouteTable выглядит следующим образом:

 export class RouteTable extends Component {

constructor(props) {
    super(props);
}

getStatus(result) {
    let status;
    if (result.customerStatus === 0) {
        status = (<Badge color={'secondary'}> Pre Journey Generation</Badge>)
    } else if(result.customerStatus === 1) {
        status = (<Badge color={'success'}> In Journey Generation</Badge>)
    } else if (result.customerStatus === 2) {
        status = (<Badge color={'info'}> Ready for Emulation</Badge>)
    } else {
        status = (<Badge href="/journeyEmulation" color={'danger'}> In Emulation</Badge>)
    }
    return status;
}

render() {
    const {startEmulation, buttonDisabled} = this.props;
    const items = this.props.results.map(result => {
        const serviceIdList = [];
        const deviceRequests = [];

        result.linkedCustomers.map(x => { const emulationData = {"imei": x.imei, "serviceId": x.serviceId, "deviceType": "CALAMP"}
            deviceRequests.push(emulationData)
        });

         result.linkedCustomers.map(x => {serviceIdList.push(x.serviceId);});

        return (
            <tr key={result.linkedCustomerId}>
                <th scope="row">{result.customerName}</th>
                <td>{result.linkedCustomerId}</td>
                <td>{result.numDevices}</td>
                <td>{result.startDate}</td>
                <td>{result.endDate}</td>
                <td>{result.lat}</td>
                <td>{result.lng}</td>
                <td> {this.getStatus(result)}</td>

                <td>
                    <div style={{width:"100%"}}>
                        <Button style={{width: "50%"}} color="primary" onClick={() => this.props.generateJourney(result.linkedCustomerId, result.startDate, result.endDate, serviceIdList, result.lat, result.lng)} disabled={buttonDisabled}>Generate Journey</Button>
                        {' '}
                        <Button style={{width: "50%", marginTop: "4%"}} color="danger" onClick={() => startEmulation(result.linkedCustomerId, result.customerName, result.startDate, result.endDate, deviceRequests)}>Emulate Journey</Button>
                    </div>
                </td>
            </tr>
        )
    })

    return (
        <div className="tableDesign" style={{marginTop: "2%"}}>
        <Table hover>
            <thead>
            <tr>
                <th>Customer Name</th>
                <th>Kinesis Customer Id</th>
                <th>Number of Devices</th>
                <th>Start Date</th>
                <th>End Date</th>
                <th>Home Lat</th>
                <th>Home Long</th>
                <th>Status</th>
                <th>Actions</th>
            </tr>
            </thead>
            <tbody>
            {items}
            </tbody>
        </Table>
        </div>
    )
}

Теперь моя проблема заключается в том, как мне запретить пользователю генерировать поездку дважды? Я пробовал опубликованное решение, которое просто отключает все кнопки для каждой строки. Любая помощь будет принята с благодарностью, так как это становится разочаровывающим!! Я предполагаю, что могу каким-то образом использовать ключ строки таблицы <tr key {result.linkedCustomerId}>, чтобы отключить конкретную кнопку?

Спасибо за вашу помощь :)

***** РЕДАКТИРОВАТЬ *****

 generateJourney = (customerId, startDate, endDate, linkedCustomers, lat, lng) => {
   let confirmGenerateJourney = window.confirm('Are you sure you want to start this Journey Generation?')
    if (confirmGenerateJourney) {

        this.setState({generatingId: customerId});

        fetch('http://10.10.52.149:8080/generate-journeys', {
            method: 'POST',
            mode:'cors',
            headers: {
                'Content-Type': 'application/json',
                'Access-Control-Allow-Origin': '*',
            },
            body: JSON.stringify( {
                customerId: customerId,
                startDate: startDate,
                endDate: endDate,
                serviceIds: linkedCustomers,
                homeLat: lat,
                homeLng: lng
            })
        }).then(response => {
            this.setState({generatingId: null});
            // response.json();
        }).catch(err => {
            this.setState({generatingId: null});
            console.log(err)
        })

        notification.success({
            message: 'Kinesis Fake Telemetry',
            description: "Journey has Started being Generated",
        });

        fetch('http://localhost:8080/api/routeGen/updateCustomerStatus', {
            method: 'PUT',
            mode:'cors',
            headers: {
                'Content-Type': 'application/json',
                'Access-Control-Allow-Origin': '*',
            },
            body: JSON.stringify( {
                customerId: customerId,
                status: 1
            })
        }).then(response => response.json())
            .catch(err => console.log(err))

        // window.location.reload();
    }
}

Реквизиты, переданные в RouteTable

 {
                !this.state.loading && this.state.results.length > 0 ? (
                    <RouteTable generatingId ={this.state.generatingId} results={this.state.results} generateJourney={this.generateJourney} startEmulation={this.getJourneyEmulations}/>
                ) : null
            }

Затем в RouteTable:

                            <Button style={{width: "50%"}} color="primary" onClick={() => this.props.generateJourney(result.linkedCustomerId, result.startDate, result.endDate, serviceIdList, result.lat, result.lng)} disabled={this.props.generatingId === result.linkedCustomerId}>Generate Journey</Button>

person Alexander Dunn    schedule 12.12.2019    source источник
comment
Если вы установите для параметра buttonDisabled значение true, отключит ли он кнопку? Просто хочу убедиться, что это не проблема с компонентом кнопки, который вы пытаетесь отключить.   -  person Edrian    schedule 12.12.2019
comment
Да, но для каждой кнопки в таблице, а не для конкретной строки!   -  person Alexander Dunn    schedule 12.12.2019


Ответы (1)


Один из способов сделать это:

  1. В вашем компоненте, использующем RouteTable, создайте новое состояние с именем generatingId.
  2. Создайте новую опору для <RouteTable> с именем generatingId и сделайте this.state.generatingId ее значением.
  3. В вашей функции generateJourney выполните this.setState({generatingId: customerId}) перед вызовом AJAX. Затем внутри .then и .catch сделайте this.setState({generatingId: null})
  4. Теперь внутри вашего компонента RouteTable обновите кнопку создания маршрута строки, чтобы она выглядела так:
<Button style={{width: "50%"}} color="primary" onClick={() => this.props.generateJourney(result.linkedCustomerId, result.startDate, result.endDate, serviceIdList, result.lat, result.lng)} disabled={this.props.generatingId === result.linkedCustomerId}>Generate Journey</Button>

Что произойдет, если вы нажмете и кнопку Generate Journey, функция generateJourney установит идентификатор клиента в качестве идентификатора, который генерируется. Это новое значение будет передано в ваш RouteTable, а затем отобразит вашу таблицу, и, поскольку кнопка строк будет проверять, равна ли опора generatingId значению customerId, для которого предназначена строка, она отключит кнопку в этой строке, если оператор правда.

person Edrian    schedule 12.12.2019
comment
Привет, я отредактировал свой ответ. Кажется, это не работает. Он отключается, а затем снова быстро возвращается к нажатию - person Alexander Dunn; 12.12.2019
comment
Итак, это работает. Однако, если я перейду на новую страницу, а затем вернусь на страницу таблицы, кнопка снова станет доступной. Как я могу обойти это? Нужно ли передавать состояние? - person Alexander Dunn; 12.12.2019