Форум программистов, компьютерный форум, киберфорум
React/ReactJS
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
 
Рейтинг 5.00/9: Рейтинг темы: голосов - 9, средняя оценка - 5.00
0 / 0 / 1
Регистрация: 27.06.2013
Сообщений: 88

Не компилируется компонент

02.02.2024, 14:46. Показов 2070. Ответов 22
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Здравствуйте. Я новичок в ReactJS, только изучаю его. Я написала небольшой компонент, но при компилации через webpack babel получаю ошибку и не понимаю, то неправильно я написала ? Подскажите, пожалуйста, мне.
Привожу код моего компонента:
JavaScript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
import React from "react";
 
class FileLoader extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            data: [{ title: "", comment: "", path: "" }]
        };
    }
 
    row() {
        return (
            {
                props.data.map((data, index) => (
                    <tr key={ index }>
                        <td><input type="text" name="title" value={ data.title } className="form-control" /></td>
                        <td><input type="text" name="title" value={ data.comment } className="form-control" /></td>
                        <td><input type="file" name="title" value={ data.path } className="form-control" /></td>
                        <td><button className="btn btn-outline-success" onClick={() => (deleteTableRows(index))} >-</button></td>
                    </tr>
 
                ))
            }
        );
    }
 
    addTableRows() {
        props.data.push({
            title: "",
            comment: "",
            path: ""
        });
    }
 
    deleteTableRows(index) {
        props.data.rows.splice(index, 1);
    }
 
    render() {
 
        return (
            <div className="container">
                <div className="row">
                    <div className="col-sm-8">
                        <table className="table">
                            <thead>
                                <tr>
                                    <th>Title</th>
                                    <th>Comment</th>
                                    <th>Путь</th>
                                    <th>Действие</th>
                                </tr>
                            </thead>
                            <tbody>
                                {row()}
                            </tbody>
                        </table>
                    </div>
                    <div className="col-sm-4">
                        <button className="btn btn-outline-success" onClick={addTableRows}>+</button>
                    </div>
                </div>
            </div>
        );
    }
}
export default FileLoader;
Скриншот ошибки:
0
Programming
Эксперт
39485 / 9562 / 3019
Регистрация: 12.04.2006
Сообщений: 41,671
Блог
02.02.2024, 14:46
Ответы с готовыми решениями:

Не компилируется компонент SpeechLib_TLB
Драстуйте помогите новичку почему RADStudio 11.1 не может компилировать SpeechLib_TLB? а на Delphi XE8 компилируется что делать?

не компилируется компонент synedit
драстуйте почему не компилируется компонент synedit ставил в libary путь где лежат исходники добавил и вроде бы установилась правильно......

не компилируется задание: компонент связности графа - кто разберется
#include &lt;iostream&gt; #include &lt;conio.h&gt; #include &lt;stdlib.h&gt; class Stack { private: int stackSize; int* stackArray; ...

22
Молодой техлид)
Эксперт JSЭксперт HTML/CSS
 Аватар для mr_dramm
1818 / 1056 / 329
Регистрация: 17.07.2021
Сообщений: 2,147
Записей в блоге: 14
02.02.2024, 15:52
функция row возвращяет объект JS, а имя поля объекта не могут быть с использованием оператора точка(как и написано в ошибке, можно использовать запятую), row должна вернуть React елемент, для этого можно поместить свой код в React.Fragment, а во вторых вызов функции должен быть с использованием this
0
0 / 0 / 1
Регистрация: 27.06.2013
Сообщений: 88
02.02.2024, 18:39  [ТС]
Благодарю вас за ответ. Я нашла как поправить свой код. Но возникла новая проблема у меня:
при клике на кнопку + которая должна добавлять строку к таблице у меня ничего не происходит, а в консоли браузера я вижу следующую ошибку:


Код моего компонента:
JavaScript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
import React from "react";
 
class FileLoader extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            data: [{ title: "", comment: "", path: "" }]
        };
    }
 
    row() {
        return (<>
            {             
                this.state.data.map((data, index) => (
                    <tr key={ index }>
                        <td><input type="text" name="title" value={ data.title } className="form-control" /></td>
                        <td><input type="text" name="title" value={ data.comment } className="form-control" /></td>
                        <td><input type="file" name="title" value={data.path} className="form-control" /></td>
                        <td><button className="btn btn-outline-success" onClick={() => (this.deleteTableRows(this.state, index))} >-</button></td>
                    </tr>
 
                ))
            }
            </>
        );
    }
 
    addTableRows() {
        console.log('!!!2');
        this.state.data.push({
            title: "w",
            comment: "w",
            path: "w"
        });
        console.log('!3 ', data);
        this.setState({ data: data });
    }
 
    deleteTableRows(state, index) {
        state.data.rows.splice(index, 1);
    }
 
    render() {
 
        return (
            <React.Fragment>
                <div className="container">
                    <div className="row">
                        <div className="col-sm-8">
                            <table className="table">
                                <thead>
                                    <tr>
                                        <th>Title</th>
                                        <th>Comment</th>
                                        <th>Путь</th>
                                        <th>Действие</th>
                                    </tr>
                                </thead>
                                <tbody>
                                    {this.row()}
                                </tbody>
                            </table>
                        </div>
                        <div className="col-sm-4">
                            <button className="btn btn-outline-success" onClick={this.addTableRows.bind(this)}>+</button>
                        </div>
                    </div>
                    </div>
                </React.Fragment>
        );
    }
}
export default FileLoader;
Я видела, что в движке ES7 изменился синтаксис создания компонентов. Но в документации по ReactJS в примере крестики нолики описан компонент созданный именно через class (https://ru.legacy.reactjs.org/... orial.html)
Мне больше нравился старый способ. Он для меня нагляднее и привычнее. Возможно ли его использовать?
Как починить тогда мой пример? Чтобы добавлялась строка к таблице ? Помогите, пожалуйста.
0
Молодой техлид)
Эксперт JSЭксперт HTML/CSS
 Аватар для mr_dramm
1818 / 1056 / 329
Регистрация: 17.07.2021
Сообщений: 2,147
Записей в блоге: 14
02.02.2024, 19:25
Цитата Сообщение от tiny developer Посмотреть сообщение
Я видела, что в движке ES7
Что за движек ES7? Если имеется ввиду стандарт, то это тут не причем, так как классы появились в js в es6 после функций, или уточните что имеется ввиду. Если я правильно понял про новый и старый способ, это вопрос про функциональные и классовые компонеты. В реакт начитая с 16 версии есть классовые и функциональные компоненты. Никто особо не запрещает пользоваться классовыми компонентами, они в основном используются в разработке, когда нужен componentDidCatch для перехвата ошибок внутри компонентов REact и других особенностей классовых коспонентов. Если вы поддерживаете React 15 то тоже там только классовые. Но функциональные компоненты сейчас в приоритете из того что, большинство библиотек использует хуки, с которыми не получится работать в классовых компонентах, классовый компонент нужно будет оборачивать в функциональный, чтобы пользоваться какой-то библиотекой с хуками.

На счет ошибки то это просто не внимательность, у вас нет переменной с именем data.
0
0 / 0 / 1
Регистрация: 27.06.2013
Сообщений: 88
05.02.2024, 18:09  [ТС]
Благодарю вас за ответ. Действительно по невнимательности не заметила ошибки. Поправила и всё заработало.
Но есть ещё один вопрос. Не получается у меня вызвать метод моего компонента, когда в другом компоненте отработала функция, забрала с сервера данные. И вот мне часть этих данных нужна в моём компоненте. Я пытаюсь сделать это так:

Код моего компонента:
JavaScript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
import React from "react";
 
class FileLoader extends React.Component {
    constructor(props) {
        super(props);
        console.log('props=',props);
        this.state = {
            data: [{ title: "", comment: "", path: "" }],
            lotId: 0
        };
    }
 
    setLotId(lotId) {
        console.log(lotId);
    }
 
    row() {
        return (<>
            {             
                this.state.data.map((data, index) => (
                    <tr key={ index }>
                        <td><input type="text" name="title" value={ data.title } className="form-control" /></td>
                        <td><input type="text" name="title" value={ data.comment } className="form-control" /></td>
                        <td><input type="file" name="title" value={data.path} className="form-control" /></td>
                        <td><button className="btn btn-outline-success" onClick={() => (this.deleteTableRows(this.state, index))} >-</button></td>
                    </tr>
 
                ))
            }
            </>
        );
    }
 
    addTableRows() {
        console.log('!!!2', this.state);
        this.state.data.push({
            title: "w",
            comment: "w",
            path: ""
        });
 
        this.setState(this.state);
    }
 
    deleteTableRows(state, index) {
        state.data.splice(index, 1);
        this.setState(state);
    }
 
    render() {
 
        return (
            <React.Fragment>
                <div className="container">
                    <div className="row">
                        <div className="col-sm-8">
                            <table className="table">
                                <thead>
                                    <tr>
                                        <th>Title</th>
                                        <th>Comment</th>
                                        <th>Путь</th>
                                        <th>Действие</th>
                                    </tr>
                                </thead>
                                <tbody>
                                    {this.row()}
                                </tbody>
                            </table>
                        </div>
                        <div className="col-sm-4">
                            <button className="btn btn-outline-success" onClick={this.addTableRows.bind(this)}>+</button>
                        </div>
                    </div>
                    </div>
                </React.Fragment>
        );
    }
}
export default FileLoader;
Кусочек кода другого компонента, собственно функция в которой я пытаюсь вызвать метод моего компнента:
JavaScript
1
2
3
4
5
    autoSave = () => {
        //console.log('autoSave');
 
        setTimeout(() => this.saveLot(false, false, () => { console.log('3!'); FileLoader.setLotId(this.state.Lot.Id) }), 100);
    }
Получаю такую ошибку:


Похоже он не видит этот метод, может надо как-то сделать его публичным? Подскажите, пожалуйста.
0
0 / 0 / 1
Регистрация: 27.06.2013
Сообщений: 88
05.02.2024, 19:07  [ТС]
Нашла как это сделать. Надо было метод пометить как static.
Остался ещё один вопрос: как мне навесить событие, чтобы при выборе файла пользователем у меня в модели обновлялось соответствующая запись, поле path ?

В этом методе я добавляю новую строку к таблице, и в ней я оставляю поле path пустым. Вот мне нужно чтобы при выборе пользователем файла, моя модель обновилась внутри компонента и я вызвала нужные мне методы тогда. Как мне это сделать ?
У меня может быть одновременно несколько файлов, и нужно чтобы обновлялся path соответствующей строки в таблице.
JavaScript
1
2
3
4
5
6
7
8
9
10
    addTableRows() {
        console.log('!!!2', this.state);
        this.state.data.push({
            title: "w",
            comment: "w",
            path: ""
        });
 
        this.setState(this.state);
    }
0
250 / 184 / 58
Регистрация: 12.03.2021
Сообщений: 1,043
06.02.2024, 09:26
Цитата Сообщение от tiny developer Посмотреть сообщение
В этом методе я добавляю новую строку к таблице, и в ней я оставляю поле path пустым. Вот мне нужно чтобы при выборе пользователем файла, моя модель обновилась внутри компонента и я вызвала нужные мне методы тогда. Как мне это сделать ?
нормально сформированный вопрос, как правило, содержит в себе ответ. а тут муть какая-то со второго предложения.
что значит "при выборе пользователем файла"? он вгружает его? он скачивает? о каких файлах вообще речь идёт?
какая модель внутри компонента обновилась?
какие методы нужные?
в целом, из всего этого могу сказать так - когда пользователь выбрал файл, нужно обновить модель и вызвать методы
0
0 / 0 / 1
Регистрация: 27.06.2013
Сообщений: 88
07.02.2024, 15:57  [ТС]
благодарю, что отвечаете мне. Я нашал как сделать то что спрашивала, но возникло у меня новое затруднение.
Я в своей компоненте сделал статический метод, чтобы его можно было вызвать из другого компонента, но не учла что мне не будет доступны никакие переменные моего компонента и указатель this. Долго искала как же сделать такой метод, чтобы он как публичный был, его можно было вызвать у моего класса-компонента, например таким образом:
JavaScript
1
FileLoader.autoSave();
не удалось мне это сделать, если подскажите буду рада. Я решила тогда, что буду в свой компонента передавать ссылку на переменную из другого компонента. И когда эта переменная изменится, то мне нужно знать это в своём компоненте и вызвать соответствующий метод. Во внешнем компоненте я так прописала использование своего компонента:
JavaScript
1
<FileLoader lotId={this.state.Lot.Id } />
Т.е. я хочу отслеживать изменения переменной this.state.Lot.Id
Я узнала что для это используют в функциональных компонентах useEffect. Но его нельзя использовать в классе компоненте.
Как быть тогда? Я бы не хотела переделывать свой компонент на функциональный, так как мне привычнее код читать через классы. Код функциональных компонентов как-то не очевиден для меня и запутан. Как раньше обходились без useEffect ? Как решали такую проблему ?
0
Эксперт JSЭксперт HTML/CSS
 Аватар для krvsa
3833 / 1677 / 431
Регистрация: 14.03.2022
Сообщений: 4,231
07.02.2024, 16:53
Цитата Сообщение от tiny developer Посмотреть сообщение
Код функциональных компонентов как-то не очевиден для меня и запутан
Функция всегда проще класса... Это как бы аксиома. Потому-то и Реакт двигают именно в сторону функциональных компонентов.

Цитата Сообщение от tiny developer Посмотреть сообщение
Как раньше обходились без useEffect ? Как решали такую проблему ?
У класса есть свои методы "жизненного цикла".

Цитата Сообщение от tiny developer Посмотреть сообщение
мне привычнее код читать через классы
Видно что и с классовыми компонентами ты не особо умеешь работать...

Т.е. пока из твоих высказываний можно понять что ты ни с чем работать не умеешь.
0
0 / 0 / 1
Регистрация: 27.06.2013
Сообщений: 88
07.02.2024, 17:04  [ТС]
скажите, пожалуйста, какие вы видите проблемы в моём классе ? Я буду только рада вашему совету, чтобы улучшить мой код.
Может мне следует что-то почитать, чтобы я умела хорошо писать код ?
0
Эксперт JSЭксперт HTML/CSS
 Аватар для krvsa
3833 / 1677 / 431
Регистрация: 14.03.2022
Сообщений: 4,231
07.02.2024, 17:25
Цитата Сообщение от tiny developer Посмотреть сообщение
какие вы видите проблемы в моём классе ?
Он довольно не оптимизирован...

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

Добавлено через 3 минуты
Цитата Сообщение от tiny developer Посмотреть сообщение
Не получается у меня вызвать метод моего компонента, когда в другом компоненте
Для этого нужно точно знать кто эти два компонента "относительно друг друга"...
0
0 / 0 / 1
Регистрация: 27.06.2013
Сообщений: 88
07.02.2024, 20:11  [ТС]
Подскажите мне, пожалуйста, как наилучшим образом оптимизировать мой код ? Я буду очень благодарна вам.
Расскажу подробнее о компонентах:
1) есть большая форма со множеством полей для создания лота в аукционе
2) я пишу небольшой компонент, который позволяет подгружать документы (файлы world,pdf)
компонент мой должен уметь делать автосохранение, на случай если пользователь закрыл вдруг вкладку.
Автосохранение лота уже есть на основной форме, куда я внедряю свой компонент. И вот я хотела сначала, чтобы когда произошло автосохранение, то вызвался и метод у моего компонента и я могла тоже асинхронно отправить документы на сервер.
Или же я подумала отслеживать состояние переменной lotId, чтобы когда произойдёт автосохранение лота и будет присвоен новому лоту Id из БД, то я получу этот Id и по нему сохраню документы.

Приведу полный код моего компонента на сегодняшний день моих усилий)
JavaScript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
import React, { useState, useEffect, useRef } from "react";
import styles from './FileLoader.css';
 
class FileLoader extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            data: [{ orderNumber: 0, id: 0, title: "", comment: "", fileName: "", file: null, autoSave: false, flagDelete: false }],
            lotId: props.lotId,
            progressBar: 15,
            sendingData: false
        };
        this.onChangeDataTextInput = this.onChangeDataTextInput.bind(this);
        this.browseFile = this.browseFile.bind(this);
        this.autoSave = this.autoSave.bind(this);
    }
 
    componentDidUpdate(prevState, prevProps) {
        this.state.lotId = this.props.lotId;
 
    }
 
    // этот метод статический, так ак нам нужен к нему доступ в другом компоненте. Вызывается этот метод в LostEditor при автосохранении лота
 
        autoSave() {
            console.log(this.state);
 
            if (lotId) {
                this.state.lotId = lotId;
 
                let len = this.state.data.length;
                let percent = 100 / len;
                this.state.data.map(function (item) {
                    if (item.file && !item.flagDelete && !item.autoSave)
                        this.loadFileOnServer(item, percent);
 
                    else if (item.flagDelete)
                        this.deleteFileFromServer(item, function (item) {
                            this.loadFileOnServer(item);
                        });
                });
            }
        }
 
    onChangeDataTextInput(e) {
        let data = e.target.name.split('_');
        let item = this.state.data[data[1]];
        item[data[0]] = e.target.value;
        this.forceUpdate();
    }
 
    // метод отправляющий файл на сервер
    loadFileOnServer(item, percent) {
        const formData = new FormData();
        formData.append("Comment", item.comment);
        formData.append("Title", item.title);
        formData.append("DocumentFile", item.file);
        formData.append("LotId", lotId.toString());
 
        Fetcher("/DocumentApi/AddDocument",
            {
                method: 'POST',
                body: formData
            })
            .then(res => res.json())
            .then(
                (result) => {
                    if (result.Success) {
 
                        item.autoSave = true;
                        item.id = result.UpdatedItem;
                        percent = this.state.progressBar + percent;
                        this.state.progressBar = percent > 100 ? 100 : percent;
                        this.state.sendingData = percent > 100 ? false : true;
                        this.forceUpdate();
                    }
                    else if (result.result.Error) {
                        console.log('error: ', result.result.Error);
                    }
                }
            );
    }
 
    // метод удаляющий файл с сервера
    deleteFileFromServer(item, callback) {
        Fetcher("/DocumentApi/RemoveDocument?id=" + item.id,
            {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json',
                }
            })
            .then(res => res.json())
            .then(
                (result) => {
                    if (result.Success) {
                        item.flagDelete = false;
                        this.forceUpdate();
                        callback();
                    }
                    else {
                        alert("Произошла ошибка!");
                    }
                });
    }
 
    row() {
        return (<>
            {             
                this.state.data.map((item, index) => (
                    <tr key={index}>
                        <td><input type="text" name={'title_'+index} value={item.title} onChange={(e) => this.onChangeDataTextInput(e)} placeholder="Informe sua senha" className="form-control app-form-control" /></td>
                        <td><input type="text" name={'comment_'+index} value={item.comment} onChange={(e) => this.onChangeDataTextInput(e)} className="form-control app-form-control" /></td>
                        <td>
                            { this.buttonFileUpload(item) }
                        </td>
                        <td><button className="btn btn-outline-success" onClick={() => (this.deleteTableRows(this.state, index))} >-</button></td>
                    </tr>
 
                ))
            }
            </>
        );
    }
 
    buttonFileUpload(item) {
        return (
            <>
                <button className="button-upload" onClick={(e) => this.browseFile(e, item)}>
              Upload a file
            </button>
              <input 
                    type="file"
                    name={"file_" + item.orderNumber}
                    id={"file_" + item.orderNumber}
                    style={{display:'none'}}
                   
                    onChange={(event) => {
                    item.file = event.target.files[0];
 
                    if (item.id > 0 && item.autoSave)
                        this.state.data[item.orderNumber].flagDelete = true;
 
                    this.forceUpdate();
                 }} 
              />
                <label>путь: {(!item.file) ? "" : item.file.name}</label>
             </>
        );
 
    }
 
    browseFile(event, item) {
        $('input[name=file_' + item.orderNumber + ']').click();
    }
 
    addTableRows() {
        this.state.data.push({
            title: "",
            comment: "",
            path: "",
            orderNumber: this.state.data.length
        });
 
        this.setState(this.state);
    }
 
    deleteTableRows(state, index) {
        state.data.splice(index, 1);
        this.setState(state);
    }
 
    render() {
 
        return (
            <React.Fragment>
                <div className="container">
                    <div className="row">
                        <div className="col-sm-12" style={{
                            opacity: this.state.sendingData ? 0.25 : 1,
                            pointerEvents: this.state.sendingData ? 'none' : 'auto'
                        }}>
                            <div id="progressbar_modalwindow_fileloader" style={{ display: this.state.sendingData ? 'block' : 'none' }}>
                            <div class="progress" >
                                    <div class="progress-bar progress-bar-striped progress-bar-animated" role="progressbar"
                                        aria-valuenow={this.state.progressBar.toString()} aria-valuemin="0" aria-valuemax="100"
                                        style={{ width: this.state.progressBar.toString() + '%' }}></div>
                            </div>
                         </div>
                            <table className="table">
                                <thead>
                                    <tr>
                                        <th>Title</th>
                                        <th>Comment</th>
                                        <th>Путь</th>
                                        <th>Действие</th>
                                    </tr>
                                </thead>
                                <tbody>
                                    {this.row()}
                                </tbody>
                            </table>
                        </div>
                        <div className="col-sm-4">
                            <button className="btn btn-outline-success" onClick={this.addTableRows.bind(this)}>+</button>
                        </div>
                    </div>
                    </div>
                </React.Fragment>
        );
    }
}
export default FileLoader;
Вот как я использую свой компонент на основной форме:
JavaScript
1
<FileLoader lotId={this.state.Lot.Id } />
Небольшая картинка внешнего вида моего компонента:

Внешне он пока не доделан, это я потом сделаю ему.

Буду рада вашим советам по улучшению кода и его оптимизации)
0
Эксперт JSЭксперт HTML/CSS
 Аватар для krvsa
3833 / 1677 / 431
Регистрация: 14.03.2022
Сообщений: 4,231
08.02.2024, 09:17
Цитата Сообщение от tiny developer Посмотреть сообщение
как наилучшим образом оптимизировать мой код ?
Начать можно с того, что не делать такие огромные компоненты-монстры. Т.е. из одного такого можно наделать несколько меньшего размера.

Цитата Сообщение от tiny developer Посмотреть сообщение
Автосохранение лота уже есть на основной форме, куда я внедряю свой компонент. И вот я хотела сначала, чтобы когда произошло автосохранение, то вызвался и метод у моего компонента и я могла тоже асинхронно отправить документы на сервер.
Если что-то происходит в материнском компоненте и об этом нужно "известить" дочерний компонент - это можно сделать пропсами, которые может "пробросить" родительский компонент до дочернего. Или изменить некий стейт который так же доступен дочернему...

Т.о. произойдет рендер дочернего компонента и он сможет выполнить нужные действия.

tiny developer, учись от "объяснений" переходить к тестовым примерам.

Добавлено через 32 минуты
tiny developer, поскольку я не использую классовые компоненты, покажу тестовый пример на функциональных.
Твой компонент, в моем примере - Test.

JavaScript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
import {useState, useEffect} from 'react';
import ReactDOM from 'react-dom/client';
 
//
function App() {
    const [date, setDate] = useState(null)
    useEffect(_ => {
        const t = setTimeout(_ => {
            // тут делается автосохранение
            const d = (new Date()).toLocaleString()
            setDate(d)
        }, 2000);
        return _ => clearTimeout(t)
    })
    return (
        <section>
            <Auto date={date} />
            <Test date={date} />
        </section>
    );
}
//
function Test({date}) {
    useEffect(_ => {
        if (!date) return
        // тут отправка на сервер
        console.log('Отправка данных на сервер...')
    })
    return <p>Тест</p>
}    
//
function Auto({date}) {
    if (!date) return <p>Данные не записаны</p>
    return <p>Автоматическая запись {date}</p>
}    
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
    <App />
);
Этот пример можно сопипастить в "пустой" реакт-проект и запустить. Посмотреть как это работает.
0
0 / 0 / 1
Регистрация: 27.06.2013
Сообщений: 88
08.02.2024, 16:29  [ТС]
спасибо вам большое! Я очень рада получить и ответ и пример кода)
0
0 / 0 / 1
Регистрация: 27.06.2013
Сообщений: 88
16.02.2024, 19:51  [ТС]
Здравствуйте. Я снова к вам за помощью и советом пришла) написав много кода своего компонента и наполовину уже его сделав, я пришла к выводу переписать на функциональный компонент. Так как мне нужны были хуки внутри моего компонента, а они не доступны. С функциональным компонентом у меня возникли трудности. Вот про них и хочу я спросить. Я решила использовать TypeScript для написания компонента.
Я бы хотела ещё раз напомнить что я хочу получить, что за компонент разрабатываю:
Это будет у меня таблица для загрузки файлов на сервер. Каждая строка таблица - отдельный файл.
В начале работы компонента мы не имеем ни одной строки в таблице. Внизу таблицы есть кнопка + которая отвечает за добавление строки в таблицу. Пи клике по ней добавляется динамически строка в таблицу с input для заполнения.
Покажу пример на картинке:

В колонке действия мы имеем две кнопки: удалить строку из таблицы и залить файл на сервер.
При клике на кнопку залить файл на сервер, мы асинхронно сохраняем файл и как только получим успешний ответ от сервера,
то строка таблицы должна измениться на другой вид:

Таким образом мы после сохранения документа на сервер имеем возможность изменить все его поля, если нужно.
Я придумала это реализовать следующим образом:
JavaScript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
import React, { useState, useEffect, useRef } from "react";
import { IModelError, Nullable } from "../../Common/types";
import Fetcher from "../Fetch";
import styles from './FileLoader.css';
import $ from 'jquery';
 
// режим строки в таблице. До загрузки на сервер и после загрузки файла на сревер
export enum Mode {
    Edit = 1,  // до загрузки файла на сервер
    Viewer = 2 // после загрузки файла на сервер
}
 
 
interface IMode {
    Mode: Mode,
    Value: any
}
interface IDocumentModel {
    DocumentId: number,
    DocumentTitle: IMode,
    Comment: IMode,
    DisplayNumber: number,  
    DocumentFile: IMode,
    DocumentFileName: string,
    IsAutoSave: boolean,
    IsError: boolean,
}
interface IPropsType {
    lotId?: Nullable<number>,
    refresh: boolean,
    prefix: string,
    onAddDocument: (string) => void
}
 
function FileLoader(props: IPropsType) {
 
    const maxFileSize = 10485760;
    const [documents, setDocuments] = useState<Array<IDocumentModel>>([]);
 
    const browseFile = (event, orderNumber) => {
        console.log('call browseFile ');
        $('input[name=file_' + orderNumber + ']').click();
    };
 
    const addTableRows = () => {
        console.log('addTableRows');
 
        var doc: IDocumentModel = {
            DocumentId: 0,
            DocumentTitle : { Mode: Mode.Edit, Value: '' } as IMode,
            Comment: { Mode: Mode.Edit, Value: '' } as IMode,
            DocumentFile: { Mode: Mode.Edit, Value: null } as IMode,
            DisplayNumber: documents.length,
            DocumentFileName: "",
            IsAutoSave: false,
            IsError: false
        };
 
        documents.push(doc);
        setDocuments(documents);  
    }
 
    const deleteTableRows = (index) => {
        documents.splice(index, 1);
        setDocuments(documents);
    }
 
    const buttonFileUpload = (item: IDocumentModel, isVisible) => {
        return (
            <>
                <div id={"buttonUploadFile_" + item.DisplayNumber} style={{ display: isVisible ? "block" : "none" }}>
                    <button className="button-upload" onClick={(e) => browseFile(e, item.DisplayNumber)}>
                        Upload a file
                    </button>
                    <input
                        type="file"
                        name={"file_" + item.DisplayNumber}
                        id={"file_" + item.DisplayNumber}
                        style={{ display: 'none' }}
                        onChange={(event) => {
                            var file = event.target.files[0];
                            documents[item.DisplayNumber].DocumentFileName = file.name;
                            documents[item.DisplayNumber].DocumentFile.Value = file;
                        }}
                    />
                    <label>{documents[item.DisplayNumber].DocumentFileName}</label>
                </div>
            </>
        );
 
    };
 
    const row = () => {
 
        return (<>
            {
 
                documents.map((item) =>
                        <React.Fragment>
                            <tr key={item.DisplayNumber}>
                                <td>
                                    {item.DocumentTitle.Mode == Mode.Edit ?
                                        <input type="text" name={'title_' + item.DisplayNumber}
                                            placeholder="введите название документа" className="form-control app-form-control"
                                            required onBlur={(e) => {
                                                documents[item.DisplayNumber].DocumentTitle.Value = e.target.value;
                                            }}
                                        />
                                    : <label>{item.DocumentTitle.Value}</label>
                                    }
                                </td>
                            <td>
                                { item.DocumentTitle.Mode == Mode.Edit ?
                                    <textarea name={'comment_' + item.DisplayNumber} className="form-control app-form-control"
                                        rows={10} required onBlur={(e) => {
                                            documents[item.DisplayNumber].Comment.Value = e.target.value;
                                        }}>
                                    </textarea>
                                    :
                                    <p>{item.Comment.Value}</p>
                                 }
                                </td>
                                <td>
                                    {buttonFileUpload(item, true)}
                                </td>
                                <td class="actions">
                                    <button className="btn btn-outline-success" onClick={() => (deleteTableRows)} >-</button><br />
                                    <button className="save btn btn-primary btn-font-14 btn-lg btn-block mobile-sm-btn px-2 mb-md-4 mb-2"> загрузить документ </button>
                                </td>
                            </tr>
                        </React.Fragment>
                )
            }
        </>
        );
    }
 
    return (
        <React.Fragment>
            <div className="container">
                <div className="row">
                    <div className="col-sm-12">
                        {/* модальное окно которое блокирует всю таблицу и показывает сообщение */}
                        <div id={props.prefix + '_modalwindow'} style={{ display: "none" }}>
                            <div class="message" >
                                <img src="/Content/images/loading_sm.gif" style={{ width: '20px' }} />
                                <span></span>
                            </div>
                        </div>
                        {/*  сообщение уведомляющее об успешном совершении дейтсвия */}
                        <div class="alert alert-success" id={props.prefix + '_alert_success'} style={{ marginBottom: '0px', display: 'none' }} role="alert">
                            <span></span>
                        </div>
                        {/*  сообщение уведомляющее об ошибке при совершении дейтсвия */}
                        <div class="alert alert-danger" id={props.prefix + '_alert_error'} style={{ marginBottom: '0px', display: 'none' }} role="alert">
                            <span></span>
                        </div>
                        <table id={props.prefix + '_table'} className="table">
                            <thead>
                                <tr>
                                    <th>Название документа</th>
                                    <th>Комментарий</th>
                                    <th>Файл</th>
                                    <th>Действие</th>
                                </tr>
                            </thead>
                            <tbody>
                                {row()}
                            </tbody>
                        </table>
                    </div>
                    <div className="col-sm-4">
                        <button className="btn btn-outline-success" onClick={addTableRows}>+</button>
 
                    </div>
                </div>
            </div>
        </React.Fragment>
    );
}
 
export default FileLoader;
Я подумала что надо как нам переключаться между двумя разными видами строки и решила завести для этого enum - режим.
И поля документа у меня имеют сложный тип - IMode. Это для того чтобы внешний вид строки поменялся после загрузки файла на сервер. Как вы думаете хороший способ я нашла или можно сделать как-то лучше и удобнее ?

У меня беда, что при клике на кнопку + у меня ничего не происходит и строка не добавляется в таблицу. Я вызываю метод addTableRows и вижу что он отработал но ничего визуально не изменилось. Что я не сделала?
Использовать здесь state как я поняла нельзя, он и недоступен. А как мне заставить обновиться компонент на странице?

И ещё вопрос. Как можно ещё реализовать выбор файла ? Мне подсказали, что можно когда пишешь на react обойтись без jquery и это приветствуется. Как тогда мне реализовать выбор файла? Ведь у меня такая кнопка будет не одна, а для каждой строки своя кнопка. Поэтому решение через useRef не подойдёт.
Очень жду ваших ответов!
0
Эксперт JSЭксперт HTML/CSS
 Аватар для krvsa
3833 / 1677 / 431
Регистрация: 14.03.2022
Сообщений: 4,231
16.02.2024, 20:26
Цитата Сообщение от tiny developer Посмотреть сообщение
Я решила использовать TypeScript
тут я тебе не помощник... Я такое не использую в своей практике.

Цитата Сообщение от tiny developer Посмотреть сообщение
У меня беда, что при клике на кнопку + у меня ничего не происходит и строка не добавляется в таблицу.
В Реакте нужно помнить главное - все отрисовывается согласно стейту. Все равно что ты делаешь.

Цитата Сообщение от tiny developer Посмотреть сообщение
решение через useRef не подойдёт
Я тебе больше скажу - useRef не для того чтобы его пихать в каждый след.

Общий совет - если не не стоит замахиваться на что-то сложное если не знаешь основ. Начни с простого. От него, шаг за шагом, дойдешь до сложного.

Добавлено через 1 минуту
Цитата Сообщение от tiny developer Посмотреть сообщение
Я придумала это реализовать следующим образом
твой компонет все еще огромен...
0
0 / 0 / 1
Регистрация: 27.06.2013
Сообщений: 88
16.02.2024, 21:30  [ТС]
Спасибо, что вы отвечаете))
0
Молодой техлид)
Эксперт JSЭксперт HTML/CSS
 Аватар для mr_dramm
1818 / 1056 / 329
Регистрация: 17.07.2021
Сообщений: 2,147
Записей в блоге: 14
17.02.2024, 02:26
tiny developer, Первый совет, используйте декомпозицию компонентов, например, компонент Row можно сделать отдельным компонентом это уменьшит сложность кода и повысит читаемость.

Цитата Сообщение от tiny developer Посмотреть сообщение
Я решила использовать TypeScript для написания компонента.
Хорошая идея вот вам пара видосов Типизация и Продвинутый (Александр Николаичев)

Цитата Сообщение от tiny developer Посмотреть сообщение
У меня беда, что при клике на кнопку +
потому что если использовать в стейтах объекты, а не простые типы данных, то определение изменение состояние объекта будет по инстансу, дока читайте раздел What’s a mutation?

JavaScript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
import "./styles.css";
import React from "react";
type Doc = {
  name: string;
  id: number;
};
 
const ViewDocs = () => {
  const refId = React.useRef(0);
  const [docs, setDocs] = React.useState<Doc[]>([]);
  const [name, setName] = React.useState("");
  const addDoc = () => {
    if (name == "") return; 
    docs.push({ name, id: refId.current });
    refId.current++;
    // wrong way setDocs(docs);
    setDocs(docs.slice());
  };
  return (
    <div>
      <div>
        {docs.map(({ name, id }) => (
          <div key={id}>{name}</div>
        ))}
      </div>
      <div>
        <input
          type="text"
          value={name}
          onChange={(e) => setName(e.target.value)}
        />
        <button onClick={addDoc}>+</button>
      </div>
    </div>
  );
};
 
export default function App() {
  return (
    <div className="App">
      <ViewDocs />
    </div>
  );
}
Использовать jquery не рекомендуют исходя из того, что React работает JSX компонентами и виртуальным деревом DOM, а jquery работает напрямую с DOM, а в реакт работать напрямую с DOM можно только через ref, больше кода, больше сложность, большк ошибок.

На счет работы с файлами input[type=file] немного отличается от input[text] это не контролируемый компонент, т.е. ему не получится value, только прочитать (просто нужно иметь это ввиду)

JavaScript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
const FileLoader = () => {
  const [selectedFile, setSelectedFile] = React.useState<File | null>(null);
 
  const handleFileChange = (e: React.ChangeEvent<HTMLInputElement>) => {
    const file = e.target.files?.[0];
    setSelectedFile(file || null);
  };
 
  return (
    <div>
      <input type="file" onChange={handleFileChange} />
      <span>Name - {selectedFile?.name}</span>
    </div>
  );
};
В остальном работа с файлами в React не отличается от нативной т.е. также используется работы с File и FileReader и FormData, в интернетах полно примеров.
0
0 / 0 / 1
Регистрация: 27.06.2013
Сообщений: 88
21.02.2024, 08:17  [ТС]
Здравствуйте ребята. Очень благодарна вам за ответы. Переписала код компонента, вынесла Row в отдельный файл.
Но столкнулась с одной трудностью и никак не знаю как её разрешить..
Почему-то у меня не перерисовывается компонент при callback после fetch...
Приведу свой код:
файл table.tsx
JavaScript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
import React, { useState, useEffect, useRef } from "react";
import TableRows from "./Row";
import Fetcher from "../Fetch";
 
interface IPropsType {
    lotId: number,
    refresh: boolean,
    prefix: string,
    onAddDocument: (string) => void
}
function AddDeleteTableRows(props: IPropsType) {
 
 
    const [rowsData, setRowsData] = useState([]);
    //режим таблицы: блокирована на время заврешения асинхронной операции или доступна пользователю
    const [mode, setMode] = useState({ isBlock: false, message: '' });
    const [error, setError] = useState({ isError: false, message: '' });
 
    const addTableRows = () => {
 
        const rowsInput = {
            DocumentId: 0,
            DocumentTitle: { Mode: 'Edit', Value: '' },
            Comment: { Mode: 'Edit', Value: '' },
            DocumentFile: { Mode: 'Edit', Value: null },
            DisplayNumber: rowsData.length,
            DocumentFileName: "",
            IsAutoSave: false,
            IsError: false
        }
        setRowsData([...rowsData, rowsInput]);
 
        if (props.lotId == 0 || props.lotId == undefined)
        {
            setMode({ isBlock: true, message: 'Подождите, пока завершится автосохранение лота...' });
            props.onAddDocument(function (lotId) {
                setMode({ isBlock: false, message: '' });
                console.log('lotId=', lotId);
                props.lotId = lotId;
            });
        }
 
    };
    const deleteTableRows = (index) => {
        const rows = [...rowsData];
        rows.splice(index, 1);
        setRowsData(rows);
    };
 
    const handleBlur = (index, evnt) => {
 
        let data = evnt.target.name.split('_');
        let name = data[0];
 
        const rowsInput = [...rowsData];
        rowsInput[index][name].Value = evnt.target.value;
        setRowsData(rowsInput);
    };
 
    const handleFileChange = (index, evnt) => {
 
        const { name, value } = evnt.target;
        const file = evnt.target.files?.[0];
        const rowsInput = [...rowsData];
        rowsInput[index].DocumentFileName = file.name;
        rowsInput[index].DocumentFile.Value = file;
        setRowsData(rowsInput);
    };
 
    /**
       метод загружающий файл на сервер. Вызывается при клике по кнопке загрузить(кнопка со стрелкой вверх)
       @param index индекс элемента в массиве документов rowsData
       @param evnt событие
   */
    const sendFileToServer = (index, evnt) =>
    {
        const rowsInput = [...rowsData];
        var item = rowsInput[index];
        console.log(item);
 
        setError({ isError: false, message: '' });
 
        let isError = false;
 
        if (item.DocumentTitle.Value == '') {
            isError = true;
            setError({ isError: true, message: 'Введите наименование документа' });
        }
 
        if (item.DocumentFile.Value == null) {
            isError = true;
            setError({ isError: true, message: 'Выберите документ' });
        }
 
        if (!isError)
        {
            console.log('!');
            item.DocumentFile.Mode = 'Uploading';
            setRowsData(rowsInput);
 
            var fn = setRowsData;
 
            // выполним загрузку файла на сервер
            const formData = new FormData();
            formData.append("DocumentFile", item.DocumentFile.Value);
            formData.append("Comment", item.Comment.Value);
            formData.append("Title", item.DocumentTitle.Value);
            formData.append("LotId", props.lotId.toString());
 
            fetcherPOST("/DocumentApi/AddDocument", formData, function (result) {
                if (result == null) {
                    setError({ isError: true, message: 'Произошла ошибка. Попробуйте позже.' });
                    item.DocumentFile.Mode = 'Edit';
                    setRowsData(rowsInput);
                }
                else if (result.Success) {
                    console.log('success');
                    item.DocumentTitle.Mode = 'View';
                    item.Comment.Mode = 'View';
                    item.DocumentFile.Mode = 'View';
                    item.DocumentId = result.UpdatedItem;
                    console.log(item, rowsInput);
                    fn(rowsInput);
                }
                else if (result.Error) {
                    console.log('error: ', result.Error);
                    setError({ isError: true, message: result.Error });
                }
            });
        }
 
 
        console.log('sendFileToServer');
    };
 
    const fetcherPOST = (url, data, callback) => {
        Fetcher(url,
            {
                method: 'POST',
                body: data
            })
            .then(res => res.json())
            .then(
                (result) => {
                    callback(result);
                }
            )
            .catch((exception) => {
                console.log('catch: ', exception);
                callback(null);
            });
    }
 
    return (
        <div className="container">
            <div className="row">
                <div className="col-sm-12" style={{ pointerEvents: !mode.isBlock ? "auto" : 'none', opacity: !mode.isBlock ? 1 : 0.3 }}>
                    {/* модальное окно которое блокирует всю таблицу и показывает сообщение */}
                    <div id={props.prefix + '_modalwindow'} style={{ display: !mode.isBlock ? "none" : 'block' }}>
                        <div class="message" >
                            <img src="/Content/images/loading_sm.gif" style={{ width: '20px' }} />
                            <span>{mode.message}</span>
                        </div>
                    </div>
                    {/*  сообщение уведомляющее об ошибке при совершении дейтсвия */}
                    <div class="alert alert-danger" id={props.prefix + '_alert_error'} style={{ marginBottom: '0px', display: !error.isError ? "none" : 'block' }} role="alert">
                        <span>{error.message}</span>
                    </div>
                    <table className="table fl_table">
                        <thead>
                            <tr>
                                <th width="30%">Название документа</th>
                                <th width="35%">Комментарий</th>
                                <th width="20%">Файл</th>
                                <th width="15%"><button className="btn btn-outline-success" onClick={addTableRows} >+</button></th>
                            </tr>
 
                        </thead>
                        <tbody>
 
                            <TableRows rowsData={rowsData} deleteTableRows={deleteTableRows} handleBlur={handleBlur}
                                handleFileChange={handleFileChange} sendFileToServer={sendFileToServer} />
 
                        </tbody>
                    </table>
 
                </div>
                <div className="col-sm-4">
 
                </div>
            </div>
        </div>
    )
 
}
export default AddDeleteTableRows
файл row.tsx
JavaScript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
import React, { useState, useRef, useId } from "react";
 
interface IPropsType {
    rowsData: [],
    deleteTableRows: (int) => void,
    handleBlur: (index, evnt) => void,
    handleFileChange: (index, evnt) => void,
    sendFileToServer: (index, evnt) => void
}
function TableRows(props: IPropsType) {
 
    //const id = useId();
    const [modeColumnTitle, setModeColumnTitle] = useState({isEdit: false});
    const [modeColumnComment, setModeColumnComment] = useState({ isEdit: false });
    const [modeColumnFile, setModeColumnFile] = useState({ isEdit: false });
    const id = useId();
 
    const buttonsActions = (modeColumn, setModeColumn) => {
 
        return (
            <>
                <img src="/Content/images/edit.png" class="fl_icon fl_edit"
                    style={{ width: '20px', display: !modeColumn.isEdit ? "block" : "none" }}
                    onClick={() => { setModeColumn({isEdit:true})  }}
                />
                <img src="/Content/images/fl_cancel.png" class="fl_icon fl_cancel"
                    style={{ width: '20px', display: modeColumn.isEdit ? "block" : "none" }}
                    onClick={() => { setModeColumn({ isEdit: false }) }}
                />
                <img src="/Content/images/fl_okey.png" class="fl_icon fl_save"
                    style={{ width: '20px', display: modeColumn.isEdit ? "block" : "none" }}
                    onClick={() => { setModeColumn({ isEdit: false }) }}
                />
            </>
        );
    }
 
    return (
 
        props.rowsData.map((data, index) => {
            const 
                {
                    DocumentId,
                    DocumentTitle,
                    Comment,
                    DocumentFile,
                    DisplayNumber,
                    DocumentFileName,
                    IsAutoSave,
                    IsError
                } = data;
            return (
 
                 <tr key={DisplayNumber}>
                    <td>
                            {DocumentTitle.Mode == 'Edit' ?
                                <input type="text" name={'DocumentTitle_' + DisplayNumber}
                                    placeholder="введите название документа" className="form-control app-form-control"
                                    onBlur={(evnt) => (props.handleBlur(index, evnt))}
                                />
                            :
                            <div>
                                <label>{DocumentTitle.Value}</label>
                                {buttonsActions(modeColumnTitle, setModeColumnTitle)}
                            </div>
                            }
                    </td>
                    <td>
                            {Comment.Mode == 'Edit' ?
                            <textarea name={'Comment_' + DisplayNumber} className="form-control app-form-control"
                                rows={10} required onBlur={(evnt) => (props.handleBlur(index, evnt))}>
                            </textarea>
                            :
                            <div>
                                <label>{Comment.Value}</label>
                                {buttonsActions(modeColumnComment, setModeColumnComment)}
                            </div>
                            }
                    </td>
                    <td>
                        {DocumentFile.Mode != 'View' ?
                            <div>
                                <label htmlFor={id}>
                                    <input type="file" text="sdf" onChange={(evnt) => (props.handleFileChange(index, evnt))} />
                                    {DocumentFileName}
                                </label>
                            </div>
                            :
                            <div>
                                <label>{DocumentFileName}</label>
                                {buttonsActions(modeColumnFile, setModeColumnFile)}
                            </div>
                         }
                            
                        </td>
                        <td class="actions">
                        <button className="btn btn-outline-danger" onClick={() => (props.deleteTableRows(index))}>x</button>&nbsp;&nbsp;
                        <button className="btn btn-outline-success" onClick={(e) => (props.sendFileToServer(index, e))}
                            style={{ display: DocumentFile.Mode != 'View' ? 'block' : 'none' }}>
                            {DocumentFile.Mode == 'Uploading'
                                ? (<img src="/Content/images/loading_sm.gif" style={{ width: '20px' }} />)
                                : (<img src="/Content/images/upload.png" style={{ width: '20px' }} />)}
                        </button>
                        </td>
                 </tr>
            )
        })
 
    )
 
}
export default TableRows;
в функции sendFileToServer у меня и возникла проблема. Следующий код не обновляет компонента, хотя и ошибки в консоли не выдаёт, и я даже вижу что rowsInput поменял значения (в консоли), но компонент в row.tsx не перерисовался..
JavaScript
1
2
3
4
5
6
7
 console.log('success');
 item.DocumentTitle.Mode = 'View';
 item.Comment.Mode = 'View';
 item.DocumentFile.Mode = 'View';
 item.DocumentId = result.UpdatedItem;
 console.log(item, rowsInput);
 fn(rowsInput);
fn это я уже пробовала разными способами. Я думала может он теряет ссылку на функцию и надо сохранить перед fetch, но это не помогло... Подскажите мне, пожалуйста, как поправить проблему ?
0
Эксперт JSЭксперт HTML/CSS
 Аватар для krvsa
3833 / 1677 / 431
Регистрация: 14.03.2022
Сообщений: 4,231
21.02.2024, 09:36
Цитата Сообщение от tiny developer Посмотреть сообщение
Почему-то у меня не перерисовывается компонент
Компонент не рендерится в двух случаях:
- не видно изменений в стейте
- не видно изменений в пропсах

Добавлено через 2 минуты
Цитата Сообщение от tiny developer Посмотреть сообщение
Следующий код не обновляет компонента
...
JavaScript
1
2
3
4
5
6
7
 console.log('success');
 item.DocumentTitle.Mode = 'View';
 item.Comment.Mode = 'View';
 item.DocumentFile.Mode = 'View';
 item.DocumentId = result.UpdatedItem;
 console.log(item, rowsInput);
 fn(rowsInput);
Если ты так обновляешь именно item - такое конечно никто не "увидит"...
У тебя должна полностью обновиться ссылка на объект, а не просто измениться некие "глубокие" свойства.

Добавлено через 31 минуту
Цитата Сообщение от tiny developer Посмотреть сообщение
Переписала код компонента
Все равно у тебя в примерах настоящая портянка...
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
inter-admin
Эксперт
29715 / 6470 / 2152
Регистрация: 06.03.2009
Сообщений: 28,500
Блог
21.02.2024, 09:36
Помогаю со студенческими работами здесь

Программа компилируется в Borland 6.0 но не компилируется в Visual Studio 2008
Ета програма компилируетса в борланде 6.0 но не компилируетса в Visualstudio 2008 и в борланде 10-м почему? #include&lt;iostream&gt; ...

Заголовочный файл, который компилируется в VS2017, не компилируется в Qt
В общем был класс &quot;Матрицы&quot;, который нормально работал в VS2017. Возникла необходимость использовать использовать его для создания...

Компилируется в С++ bulder 6.0 но не компилируется в VS 2010 express
Здравствуйте. есть небольшая программка которая с успехом компилируется в borland C++ builder 6.0 но не в какую не хочет компилироваться...

В формате .cpp код компилируется, а в .c не компилируется
1).Подскажите почему в формате .cpp код компилируется, а в .c не компилируется 2). Как сделать так, чтобы компилировалось в .c? ...

Записать в файл G наибольшее значение из первых 5 компонент, затем - следующих 5 компонент и т.д
Дан файл F, компоненты которого являются целыми числами. Записать в файл G наибольшее значение из первых 5 компонент, затем - следующих 5...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
20
Ответ Создать тему
Новые блоги и статьи
Символьное дифференцирование
igorrr37 13.02.2026
/ * Логарифм записывается как: (x-2)log(x^2+2) - означает логарифм (x^2+2) по основанию (x-2). Унарный минус обозначается как ! */ #include <iostream> #include <stack> #include <cctype>. . .
Камера Toupcam IUA500KMA
Eddy_Em 12.02.2026
Т. к. у всяких "хикроботов" слишком уж мелкий пиксель, для подсмотра в ESPriF они вообще плохо годятся: уже 14 величину можно рассмотреть еле-еле лишь на экспозициях под 3 секунды (а то и больше),. . .
И ясному Солнцу
zbw 12.02.2026
И ясному Солнцу, и светлой Луне. В мире покоя нет и люди не могут жить в тишине. А жить им немного лет.
«Знание-Сила»
zbw 12.02.2026
«Знание-Сила» «Время-Деньги» «Деньги -Пуля»
SDL3 для Web (WebAssembly): Подключение Box2D v3, физика и отрисовка коллайдеров
8Observer8 12.02.2026
Содержание блога Box2D - это библиотека для 2D физики для анимаций и игр. С её помощью можно определять были ли коллизии между конкретными объектами и вызывать обработчики событий столкновения. . . .
SDL3 для Web (WebAssembly): Загрузка PNG с прозрачным фоном с помощью SDL_LoadPNG (без SDL3_image)
8Observer8 11.02.2026
Содержание блога Библиотека SDL3 содержит встроенные инструменты для базовой работы с изображениями - без использования библиотеки SDL3_image. Пошагово создадим проект для загрузки изображения. . .
SDL3 для Web (WebAssembly): Загрузка PNG с прозрачным фоном с помощью SDL3_image
8Observer8 10.02.2026
Содержание блога Библиотека SDL3_image содержит инструменты для расширенной работы с изображениями. Пошагово создадим проект для загрузки изображения формата PNG с альфа-каналом (с прозрачным. . .
Установка Qt-версии Lazarus IDE в Debian Trixie Xfce
volvo 10.02.2026
В общем, достали меня глюки IDE Лазаруса, собранной с использованием набора виджетов Gtk2 (конкретно: если набирать текст в редакторе и вызвать подсказку через Ctrl+Space, то после закрытия окошка. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru