我正在为<a href="https://stackoverflow.com/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="b9cbdcd8dacdf98881978b9789" rel="noreferrer noopener nofollow">[email protected]</a>
中的 vert 应用程序做CRUDL , <a href="https://stackoverflow.com/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="4331262220376e312c3637263103756d7b6d72" rel="noreferrer noopener nofollow">[email protected]</a>
。当我第一次单击 navBar 元素(即宠物)时,它会正确显示带有后端元素的表,这些元素是每个对象(单个宠物/所有者数据)的单独 JSON 文件,由文件夹上的实体(即 . ./data/pets/jsdnsj12.json),但是,当我单击导航栏上的另一个元素(即所有者)时,表格不会使用正确的后端元素重新渲染/更新,直到刷新页面。
注:Page
是可重用的函数,根据实体(即宠物、所有者)呈现元素(表格、模式、操作菜单)。
/pets 路径呈现一个包含已注册宠物信息的表格。该表的列是宠物名称、宠物主人和宠物类型(狗、猫等)。另一方面,/owners 路径显示所有者的名字/姓氏及其身份证件(驾驶执照、出生证明等)。最初单击时,每个实体都会正确显示表中的数据,但如果您尝试更改为其他路径(即从/pets 到/owners,或反之亦然),表中的第一个实体数据将保持不变,不会更新到相应的新路径/实体(除非刷新页面)。
这是 App.js。注:<RootLayout/>
集成了NavigationBar
和Outlet
组件来自react-router-dom
const router = createBrowserRouter(
createRoutesFromElements(
<Route path="/" element={<RootLayout />}>
<Route
key={"/pets"}
path="pets"
element={<Page title="Pets" entity="pets" />}
/>
<Route
key={"/owners"}
path="owners"
element={<Page title="Owners" entity="owners" />}
/>
</Route>
)
)
function App() {
return (
<RouterProvider router={router} />
);
}
Page.js
class Page extends Component {
constructor(props){
super(props);
this.state = {
showModal: false,
entities: [],
object: {},
objectId: null,
method: "POST",
columns: [],
options: initialOptions,
search: '',
vet: "",
pet: "",
};
}
/*
* showEntity is supposed to re render the table as well, but
* it only renders the actions menu
*/
showEntity = async (_event = null) => {
if (_event) {
_event.preventDefault();
}
const { entity } = this.props;
const { search, columns, vet, pet } = this.state;
const entities = await listEntity({ entity, search, columns, vet, pet });
let _columns = [];
if (Array.isArray(entities) && entities.length > 0) {
_columns = Object.keys(entities[0]).filter((col) => col !=="id") || [];
}
this.setState({ entities, columns: _columns });
};
componentDidMount() {
const { entity } = this.props;
if (entity === "owners") {
this.getBackendOptions({});
return;
}
this.showEntity();
};
/*
* Now, in render, the <ActionsMenu/> component does re render,
* which is expected, but the <Table/> component does not
*/
render() {
const { title = "unnamed", entity } = this.props;
const {columns, objectId, entities, object, options} = this.state;
return (
<>
<ActionsMenu
changeModal={ this.changeModal }
title={title}
handleSearchInput={this.handleSearchInput}
search={this.showEntity}
entity={entity}
options={options}
/>
<Table
entities= {entities}
editEntity={this.editEntity}
deleteEntity={this.deleteEntity}
columns={columns}
/>
Table.js:表头。 r和table row分别接收index和state的数据
function Table({
entities = [],
editEntity = () => {},
deleteEntity = () => {},
columns = [],
}) {
return (
<table className="table table-stripped table-hover">
<TableHeader columns={columns} />
<tbody id="table-list">
{entities.map((entity, index) => (
<TableRow
key={`row-${index}`}
index={entity.id ? entity.id : false}
entity={entity}
editEntity={editEntity}
deleteEntity={deleteEntity}
columns={columns}
/>
))}
</tbody>
</table>
);
}
NavigationBar.js
function NavigationBar() {
return (
<>
<input type="checkbox" id="check" />
<nav className="navbar">
<div className="icon"><b>P</b>ethical</div>
<ul>
<li className="nav-item">
<NavLink className="nav-link" to={"/"} end>
Home
</NavLink>
</li>
<li className="nav-item active">
<NavLink className="nav-link" to={'/pets'} end>
Pets
</NavLink>
</li>
<li className="nav-item">
<NavLink className="nav-link" to={'/owners'} end>
Owners
</NavLink>
</li>
</ul>
<label htmlFor="check" className="bar">
<span className="faBars" id="bars"><FaBars/></span>
<span className="faTimes" id="times"><FaTimes/></span>
</label>
</nav>
</>
);
}
请注意,this.getBackendOptions 正在引用一个异步函数,该函数显示宠物 - 所有者之间关系的整个对象(宠物需要有一个所有者,因此 getBackendOptions 会带来整个所有者 JSON 文件并将其显示在宠物表中的“所有者”列)。
getBackendOptions = async (newState) => {
const {options} = this.state;
const petsPromise = listEntity({ entity: "pets" });
const ownersPromise = listEntity({ entity: "owners" });
let [pet = [], owner = [] = await Promise.all([
petsPromise,
ownersPromise,
]);
pet = pet.map((_pet, index) => ({
value: _pet.id,
tag: `${_pet.petName} (${_pet.petType})`,
}));
const newOptions = {...options, pet, owner};
this.setState({ ...newState, options: newOptions }, () => {
this.showEntity();
});
};
提前致谢。
最佳答案
我不太明白完整代码的总体作用,但我高度怀疑问题是当同一组件在多个路由上呈现时,路由内容优化 react-router
所做的事情通过保持其安装并简单地使用更新的路由上下文值(即任何路由路径参数、当前location
对象等)重新渲染它。
一个简单的修复方法是为每个路由组件分配一个 React 键。 看起来这可能就是您尝试使用 Route
组件上的键执行的操作。将键移至 Page
组件,该组件在 "/pets"
和 "/owners"
路由之间导航时实际保持安装状态。
const router = createBrowserRouter(
createRoutesFromElements(
<Route path="/" element={<RootLayout />}>
<Route
path="pets"
element={<Page key="pets" title="Pets" entity="pets" />}
/>
<Route
path="owners"
element={<Page key="owners" title="Owners" entity="owners" />}
/>
</Route>
)
);
有些人可能会认为这有点“hackish”,并且它会为 React 创建(稍微)更多工作,因为它现在将拆除(即卸载)的前一个“实例” >Page
组件并安装一个新的“实例”。
更正确的版本/实现是处理组件生命周期中的路由路径更改,例如实现 componentDidUpdate
生命周期方法来运行与 componentDidMount
完全相同的逻辑,但仅当路径更改时。在这里使用 entity
属性应该足够了,因为它与路径同时更改。
示例:
class Page extends Component {
constructor(props){
....
}
showEntity = async (_event = null) => {
....
};
setData = () => {
const { entity } = this.props;
if (entity === "owners") {
this.getBackendOptions({});
return;
}
this.showEntity();
}
componentDidMount() {
this.setData();
};
componentDidUpdate(prevProps) {
if (prevProps.entity !== this.props.entity) {
this.setData();
}
}
....
关于javascript - react : Table with backend elements does not re-render when clicking a NavLink in the NavBar,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/75739926/