Реагируйте, вставляя компонент в таблицу между 2 строками динамически

#javascript #html #reactjs

Вопрос:

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

Это код, который я пробовал.

 addRow = (idx) =gt; {  const table = document.getElementById("allocatorTable");  const row = table.insertRow(idx   1);  row.className = "editorRow";  const cell1 = row.insertCell(0);  cell1.colspan = "10";  cell1.appenChild(lt;TransactionRuleEditor /gt;);  };   

Конечно, приложение lt;TransactionRuleEditor /gt; не будет работать, но оно дает вам представление о том, чего я пытаюсь достичь.

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

Есть идеи, пожалуйста? Малкольм

Комментарии:

1. Вы не мутируете DOM напрямую при использовании react. Измените состояние компонента и сделайте так, чтобы компонент всегда возвращал правильное представление состояния. Позвольте реакции применять мутации DOM так, как она хочет.

2. Просто для ясности lt;TransactionRuleEditor /gt; , это не элемент DOM или HTML. Эта строка будет скомпилирована в вызов функции jsx(TransactionRuleEditor) , которая возвращает POJO.

3. Это классовый компонент. Я понимаю, о чем ты говоришь, но я все еще не знаю, как это объяснить.

Ответ №1:

Когда вы используете React (или любой другой фреймворк, подобный MVC), вы не работаете напрямую с DOM подобным образом, вы придерживаетесь другого мышления: вы меняете состояние того, что визуализируется, а затем фреймворк выполняет визуализацию. В этом случае у вас может быть компонент, предоставляющий строку таблицы, в состоянии, когда он фактически предоставляет две строки (завернутые во фрагмент) при нажатии кнопки.

Вот упрощенный пример:

 const {useState, Component} = React;  class Row extends Component {  constructor(props) {  super(props);  this.state = {  adding: false,  };  this.onAdd = this.onAdd.bind(this);  this.onDone = this.onDone.bind(this);  }   onAdd() {  this.setState({adding: true});  }   onDone() {  // (Obviously you'd do more here)  this.setState({adding: false});  }   render() {  const {adding} = this.state;  const {data} = this.props;  const row = lt;trgt;  lt;tdgt;{data.a}lt;/tdgt;  lt;tdgt;{data.b}lt;/tdgt;  lt;tdgt;{data.c}lt;/tdgt;  lt;tdgt;{!adding amp;amp;  lt;input type="button" onClick={this.onAdd} value="Add" /gt;  }lt;/tdgt;  lt;/trgt;;  if (!adding) {  return row;  }  return lt;React.Fragmentgt;  {row}  lt;trgt;  lt;td colSpan={3}gt;  The inputs go here.  lt;/tdgt;  lt;tdgt;  lt;input type="button" onClick={this.onDone} value="Done" /gt;  lt;/tdgt;  lt;/trgt;  lt;/React.Fragmentgt;;  } }  // Or with hooks: // const Row = ({data}) =gt; { // const [adding, setAdding] = useState(false); // const row = lt;trgt; // lt;tdgt;{data.a}lt;/tdgt; // lt;tdgt;{data.b}lt;/tdgt; // lt;tdgt;{data.c}lt;/tdgt; // lt;tdgt;{!adding amp;amp; // lt;input type="button" onClick={() =gt; setAdding(true)} value="Add" /gt; // }lt;/tdgt; // lt;/trgt;; // if (!adding) { // return row; // } // // (You might memoize the callbacks via `useCallback`) // return lt;React.Fragmentgt; // {row} // lt;trgt; // lt;td colSpan={3}gt; // The inputs go here. // lt;/tdgt; // lt;tdgt; // lt;input type="button" onClick={() =gt; /* Obviously you'd do more here */ setAdding(false)} value="Done" /gt; // lt;/tdgt; // lt;/trgt; // lt;/React.Fragmentgt;; // }  const Example = () =gt; {  const [items] = useState([  {key: 1, a: "a1", b: "b1", c: "c1"},  {key: 2, a: "a2", b: "b2", c: "c2"},  {key: 3, a: "a3", b: "b3", c: "c3"},  ]);  return lt;tablegt;  lt;tbodygt;  {items.map(item =gt; lt;Row key={item.key} data={item} /gt;)}  lt;/tbodygt;  lt;/tablegt;; };  ReactDOM.render(lt;Example /gt;, document.getElementById("root")); 
 td {  width: 70px; } 
 lt;div id="root"gt;lt;/divgt;  lt;script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.2/umd/react.development.js"gt;lt;/scriptgt; lt;script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.2/umd/react-dom.development.js"gt;lt;/scriptgt; 

(В этом примере используется lt;React.Fragmentgt; , потому что версия Babel в фрагментах стека очень устарела, но в вашем реальном коде вы можете использовать lt;gt; ее вместо этого.)

Конечно, это всего лишь набросок. Но это дает вам представление о том, как можно использовать состояние для обработки этой модальности.

Комментарии:

1. Спасибо большое за помощь. Я не мог изменить DOM напрямую, но не знал другого способа сделать это.