Каков правильный шаблон в жизненном цикле ReactJS (v. 16.4) для отображения данных в дочернем компоненте из componentDidMount в родительском компоненте?
У меня есть сценарий, который должен быть достаточно простым, но он ведет себя не так, как я ожидаю. Я хочу передать данные из родительского компонента в дочерний компонент, который, в свою очередь, преобразует данные во что-то, что может быть отображено.
Я прочитал эту статью https://reactjs.org/blog/2018/06/07/you-probably-dont-need-derived-state.html, и пытаюсь получить правильный шаблон.
Раньше я использовал для этого componentWillMount
, и это работало нормально, но, как я уже сказал, он ведет себя странно с componentDidMount
.
Мой родительский компонент получает данные в своем componentDidMount
, который обновляет состояние, которое затем передается дочернему компоненту:
class NewTable extends Component {
constructor(props) {
super(props);
this.state = {
dataSet: {}
}
}
componentDidMount() {
const dataSet = DataSet.getColorDataSet();
this.setState({
dataSet: dataSet
});
}
render() {
return (
<div className="example">
<h2>HTML Table</h2>
<NewKSParser.HTMLTable dataSet={this.state.dataSet} id="myid" />
</div>
);
}
}
export default NewTable;
Мой дочерний компонент должен затем взять dataSet
из реквизита и отобразить его:
export class HTMLTable extends Component {
constructor(props) {
super(props);
this.state = {
columns: [],
rows: []
}
}
componentDidUpdate(prevProps, prevState) {
if (prevProps.dataSet !== this.props.dataSet) {
this.createTableData();
}
}
createTableData = () => {
const dataSet = { ...this.props.dataSet };
const rows = dataSet.dataSets ? dataSet.dataSets[0].rows : [];
const metaCols = dataSet.dataSets ? dataSet.dataSets[0].metadata.columns : [];
const columns = this.generateColumns(metaCols);
this.setState({
columns: columns,
rows: rows
});
}
generateColumns = (metaCols) => {
const columns = metaCols.map((col) => {
let obj = {};
obj.id = col.id;
obj.index = col.index;
obj.title = col.title;
return obj;
});
return columns;
};
render() {
const { rows, columns } = this.state;
const tableHeader = columns.map((column) => {
return <th key={column.id}>{column.title}</th>
});
const tableCells = rows.map((row, idx1) => {
return (<tr key={'row_' + idx1}>
{row.cells.map((cellContent, idx2) => <td key={`cell_${idx1}_${idx2}`}>{cellContent}</td>)}
</tr>);
});
return (
<table id={this.props.myid} key={this.props.myid}>
<thead>
<tr>
{tableHeader}
</tr>
</thead>
<tbody>
{tableCells}
</tbody>
</table>
);
}
}
Как вы можете видеть, я поместил этот код в componentDidUpdate
, потому что я совсем не заставлял его работать при использовании метода componentDidMount
дочернего элемента.
Мне кажется странным помещать его в componentDidUpdate
, и я не знаю, правильно ли это.
Вторая проблема, с которой я сталкиваюсь, заключается в том, что она отображается нормально при первом посещении страницы, но если я перехожу на другую страницу (в реакции-маршрутизатора) и затем возвращаюсь, данные в ячейках таблицы исчезают. Это может быть связано либо с неправильной реализацией жизненного цикла, либо с тем, что что-то не так с моими ключами ... Я не знаю.
UPDATE:
Это мой код маршрутизации:
class KnowledgeSets extends Component {
render() {
return (
<Router>
<main>
<TopMenu />
<Switch>
<Route exact path="/" render={()=><Home {...this.props} />} />
<Route path="/example" render={()=><Example {...this.props} />} />
<Route path="/htmltablecomponent" render={()=><Table {...this.props} />} />
<Route path="/complexexpandable" render={()=><ComplexExpandable {...this.props} />} />
<Route path="/newdataviewer" render={()=><NewDataViewer {...this.props} />} />
<Route path="/newhtmltablecomponent" render={()=><NewTable {...this.props} />} />
<Route path="/search" render={()=><Search {...this.props} />} />
</Switch>
</main>
</Router>
);
}
}
export default KnowledgeSets;
А если я изменю дочерний компонент на ...
componentDidMount() {
console.log(this.props.dataSet);
this.createTableData();
}
зарегистрированный вывод {}
. Он никогда не обновляется, даже если состояние родителя изменилось.