- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我刚开始学习 React
我正在研究我想使用 React 创建树状表的解决方案。
所以基本上功能就像有一个简单的表格,每一行都有条件展开图标,我实现了当我点击行时渲染另一个行组件的基本功能。
我实现的基本解决方案是,每当用户单击任何我调用的函数展开行时,都会在该单击的行数组下添加静态子项,并使用将子对象传递给子行组件来显示它。
现在我希望每当用户点击展开的行子项时,它应该展开到下一级并显示与第二次展开相关的数据。
所以基本上它看起来像
- Row 1
- Child 1
- Child 1.1
- Child 1.2
+ Child 2
+ Row 2
我使用来自 jsonplaceholder api 的静态 json 数据创建了基本原型(prototype)
这是代码
App.js
import React, { useState, Fragment } from "react";
import TableRowData from "./TableRowData";
import "./styles.css";
export default function App() {
const [splits, setSplit] = useState(["campid", "appid", "os"]);
return (
<Fragment>
<table>
<thead>
<tr>
<th>Id</th>
<th>Name</th>
</tr>
</thead>
<tbody>
<TableRowData avaliableSplits={splits} />
</tbody>
</table>
</Fragment>
);
}
TableRowData.js
import React, { useState, useEffect, useRef, Fragment } from "react";
import axios from "axios";
import SubRow from "./SubRow";
class TableRowData extends React.Component {
state = { data: [] };
constructor(props) {
super(props);
}
componentDidMount() {
axios.get("https://jsonplaceholder.typicode.com/users").then((res) => {
this.setState({ data: res.data });
});
}
render() {
const updateState = (id, itemAttributes) => {
var index = this.state.data.findIndex((x) => x.id === id);
if (index !== -1) {
this.setState({
data: [
...this.state.data.slice(0, index),
Object.assign({}, this.state.data[index], itemAttributes),
...this.state.data.slice(index + 1)
]
});
}
};
const expandRow = (user) => {
user.children = [
{ id: "6656", name: "sfsdfds1" },
{ id: "66563", name: "sfsdfds2" }
];
// this.setState({data:[...this.state.data],})
updateState(user.id, { isExpanded: true });
};
const collapseRow = (user) => {
user.children = undefined;
updateState(user.id, { isExpanded: false });
};
if (this.state.data) {
const appData = this.state.data.map((user) => {
return (
<Fragment key={user.id}>
<tr key={user.id}>
<td>
{user.isExpanded === true ? (
<button type="button" onClick={() => collapseRow(user)}>
-
</button>
) : (
<button type="button" onClick={() => expandRow(user)}>
+
</button>
)}
{user.id}
</td>
<td>{user.name}</td>
</tr>
{!!user.children && <SubRow rowData={user.children} />}
</Fragment>
);
});
return <Fragment>{appData}</Fragment>;
} else {
return null;
}
}
}
export default TableRowData;
子行.js
import React, { useState, useEffect, useRef, Fragment } from 'react';
import axios from 'axios';
const SubRow = (props) => {
const appData = props.rowData.map((user) => {
user.isExpanded = false;
return (
<Fragment key={user.id}>
<tr key={user.id}>
<td><button type='button' onClick={()=>handleClick(user,props.reportData)}>+</button>{user.id}</td>
<td>{user.name}</td>
</tr>
{!!user.children && <SubRow rowData={user.children} />}
</Fragment>
)
});
return (
<Fragment>{appData}</Fragment>
)
}
export default SubRow
这是codesandbox的实现Nested table
我不想为此使用任何外部包。请帮忙
添加条件展开折叠场景
我想根据我正在维护的数组进行扩展
假设我有一个数组拆分 [a,b,c],如果为此数组第一级行设置的值现在将包含与 A 相关的数据,每当使用点击 B 时,我将使用行数据发出 AJAX 请求A 的行并用展开图标显示 B 的行,因为这将是 3 级树表,类似地,每当用户单击 C 时,我都会发送 b 的数据并检索 C 的数据。现在 D 将不会进一步展开,因为数组大小为 3 ,每当用户在数组中添加第 4 个元素时,我必须在 C 上看到展开图标。
尝试 1:
import React, { useState, useEffect, useRef, Fragment } from "react";
import _ from 'lodash';
import axios from "axios";
import {connect} from 'react-redux';
import {getChildren} from '@src/redux/actions/reports';
class TableRowData extends React.Component {
state = {
showIcon: false,
selection: [],
data: []
};
constructor(props) {
super(props);
}
componentDidMount() {
axios.get("https://jsonplaceholder.typicode.com/users").then((res) => {
const rowData = res.data.map((row) => {
row.isExpanded = false;
return row;
});
this.setState({ data: rowData });
});
}
render() {
const updateState = (id, itemAttributes) => {
var index = this.state.data.findIndex((x) => x.id === id);
if (index !== -1) {
this.setState({
data: [
...this.state.data.slice(0, index),
Object.assign({}, this.state.data[index], itemAttributes),
...this.state.data.slice(index + 1)
]
});
}
};
const expandRow = (row) => {
const index = _(this.state.data)
.thru(function(coll) {
return _.union(coll, _.map(coll, 'children') || []);
})
.flattenDeep()
.findIndex({ id: row.id });
if (index !== -1) {
let prevState = [...this.state.data];
let el = _(prevState)
.thru(function(coll) {
return _.union(coll, _.map(coll, 'children') || []);
})
.flattenDeep()
.find({ id: row.id });
el.children = [
{ id: '_' + Math.random().toString(36).substr(2, 5), name: row.id+"_ID1", isExpanded:false,parentId:row.id },
{ id: '_' + Math.random().toString(36).substr(2, 5), name: row.id+"_ID2ß",isExpanded:false,parentId:row.id },
];
el.isExpanded=true;
this.setState({data:[...this.state.data],prevState},()=>{})
}
};
const collapseRow = (user) => {
delete user.children
// updateState(user.id, { children: {id:1,name:'JANAK'} });
updateState(user.id, { isExpanded: false });
};
const ExpandableTableRow = ({rows}) => {
//console.log(rows);
if (rows) {
return rows.map((row) => {
let children = null;
return (
<Fragment key={row.id}>
<tr key={row.id}>
<td>
<ExpandCollapsToggle row={row} /> {row.id}
</td>
<td>{row.name}</td>
</tr>
<ExpandableTableRow rows={row.children} />
</Fragment>
)
}
);
} else {
return null;
}
};
const ExpandCollapsToggle = ({row,actions}) => {
if(row.isExpanded === true) {
return (<button type="button" onClick={() => collapseRow(row)}>-</button>)
} else {
return (<button type="button" onClick={() => expandRow(row)}>+</button>)
}
}
if (this.state.data) {
return (
<Fragment>
<ExpandableTableRow rows={this.state.data} />
</Fragment>
);
} else {
return null;
}
}
}
const mapStateToProps = (state) => {
return {"data":state.reportReducer.data};
// return state;
}
export default connect(mapStateToProps,{getChildren})(TableRowData);
最佳答案
import React, { useRef, useState, useEffect } from "react";
import axios from 'axios';
import "./style.css";
function ExpandableRow({
loadData = new Promise(resolve => resolve([])),
onExpand,
columns,
id,
row
}) {
/* added condition to test if not first render
* if yes then added data through reference which
* will update the state but because state is
* updated directly render would not occur
* to handle this issue `onExpand` function
* is passed from parent to child which will update
* state with new data which will intern cause rendering
*/
const [rowState, setRowState] = useState(1);
const didMount = useRef(false);
useEffect(() => {
if (didMount.current) {
if (row.hasOwnProperty("children")) {
delete row["children"];
onExpand("remove", id, row);
} else {
setRowState(2);
loadData(id, row).then(data => {
row['children'] = data;
onExpand("add", id, row);
setRowState(3);
});
}
} else didMount.current = true;
}, [rowState]);
return (
<tr>
<td>
<button
type="button"
onClick={() => {
setRowState(rowState == 3 ? 1 : 3);
}}
>
{rowState == 2 ? "o" : rowState == 3 ? '-' : "+"}
</button>
</td>
{columns.map((column, idx) => (
<td key={idx}>{row[column]}</td>
))}
</tr>
);
}
// function for recursively creating table rows
function ExpandableRowTable({ loadData, onExpand, columns, rows }) {
return rows.map((row, idx) => {
const actions = {
loadData,
onExpand
};
return (
<React.Fragment>
<ExpandableRow
id={idx}
columns={columns}
row={row}
{...actions}
/>
{row.children && (
<ExpandableRowTable
columns={columns}
rows={row.children}
{...actions}
/>
)}
</React.Fragment>
);
});
}
function apiData() {
return axios.get("https://jsonplaceholder.typicode.com/users")
.then((res) => {
return res.data;
});
}
let count = 0;
const columns = ["id", "name"];
export default function App() {
const [rows, setRows] = useState([]);
useEffect(() => {
apiData().then((data) => {
count = data.length;
setRows(data)
})
.catch(err => {
console.log(err);
})
}, []);
return (
<div>
<table>
<thead>
<tr>
<th />
{columns.map((c, idx) => (
<th key={idx}>{c}</th>
))}
</tr>
</thead>
<tbody>
<ExpandableRowTable
loadData={(id, row) => {
return new Promise((resolve) => {
setTimeout(() => {
resolve([
{
id: count + 1,
name: `- ${row["name"]}`
},
{
id: count + 2,
name: `- ${row["name"]}`
}
]);
count += 2
}, 1000);
})
}}
onExpand={(action, id, row) => {
if (action == "remove") {
count -= 2
}
setRows([...rows]);
}}
columns={columns}
rows={rows}
/>
</tbody>
</table>
</div>
);
}
解决方案 1 有效 example
import React, {
createContext,
useContext,
useRef,
useState,
useReducer,
useEffect
} from "react";
import axios from "axios";
import "./style.css";
const data = {
rows: [
{
id: 1,
name: "leanne graham"
},
{
id: 2,
name: "ervin howell"
},
{
id: 3,
name: "clementine bauch"
}
],
options: {
"": null,
cities: [
{
id: 1,
name: "delhi"
},
{
id: 2,
name: "pune"
},
{
id: 3,
name: "hyderabad"
}
],
network: [
{
id: 1,
name: "unknown"
},
{
id: 2,
name: "known"
},
{
id: 3,
name: "KNOWN"
}
]
}
};
const initialState = {
showIcon: false,
selection: [],
rows: []
};
const store = createContext(initialState);
const { Provider, Consumer } = store;
const StateProvider = ({ children }) => {
const [state, dispatch] = useReducer((state, action) => {
// console.log(state.rows);
switch (action.type) {
case "ADD_SELECTION":
if (state.selection.indexOf(action.payload) == -1) {
const newState = {...state};
newState['selection'].push(action.payload);
return newState;
}
return state;
case "SET_ROWS":
return Object.assign({}, state, {
rows: action.payload
});
case "TOGGLE_ICON":
return Object.assign({}, state, {
showIcon: !state.showIcon
});
default:
return state;
}
}, initialState);
return (
<Provider
value={{
state,
dispatch,
toggleIcon: () => {
dispatch({
type: "TOGGLE_ICON"
});
},
addSelection: value => {
dispatch({
type: "ADD_SELECTION",
payload: value
});
},
setRows: rows => {
dispatch({
type: "SET_ROWS",
payload: rows
});
}
}}
>
{children}
</Provider>
);
};
/*
1 - Loading (o)
2 - Plus (+)
3 - Minus (-)
*/
function ExpandableRow({
showIcon,
loadData = new Promise(resolve => resolve([])),
onExpand,
columns,
id,
row
}) {
/* added condition to test if not first render
* if yes then added data through reference which
* will update the state but because state is
* updated directly render would not occur
* to handle this issue `onExpand` function
* is passed from parent to child which will update
* state with new data which will intern cause rendering
*/
const [rowState, setRowState] = useState(2);
const didMount = useRef(false);
useEffect(() => {
if (didMount.current) {
if (row.hasOwnProperty("children")) {
if (rowState == 2) {
delete row["children"];
onExpand("remove", id, row);
}
} else {
setRowState(1);
didMount.current = false;
loadData(id, row).then(_data => {
row["children"] = _data;
onExpand("add", id, row);
setRowState(3);
});
}
} else didMount.current = true;
}, [rowState]);
return (
<tr>
<td>
{showIcon && (
<button
type="button"
onClick={() => {
setRowState(rowState == 3 ? 2 : 3);
}}
>
{rowState == 1 ? "o" : rowState == 3 ? "-" : "+"}
</button>
)}
</td>
{columns.map((column, idx) => (
<td key={idx}>{row[column]}</td>
))}
</tr>
);
}
// function for recursively creating table rows
function ExpandableRowTable({ showIcon, loadData, onExpand, columns, rows }) {
return rows.map((row, idx) => {
const actions = {
loadData,
onExpand
};
return (
<React.Fragment key={idx}>
<ExpandableRow
id={idx}
showIcon={showIcon}
columns={columns}
row={row}
{...actions}
/>
{row.children && (
<ExpandableRowTable
showIcon={showIcon}
columns={columns}
rows={row.children}
{...actions}
/>
)}
</React.Fragment>
);
});
}
function apiData(requestData) {
console.log(requestData);
return axios.get("https://jsonplaceholder.typicode.com/users").then(res => {
return res.data;
});
}
const columns = ["id", "name"];
function Select(props) {
const { state, toggleIcon, addSelection } = useContext(store);
const { selection } = state;
return (
<div>
<div>{selection.join(", ")}</div>
<select
value={""}
onChange={evt => {
selection[selection.length - 1] != evt.target.value && toggleIcon();
addSelection(evt.target.value);
}}
>
{Object.keys(data.options).map((c, idx) => (
<option key={idx}>{c}</option>
))}
</select>
</div>
);
}
function Table(props) {
const { state, toggleIcon, setRows } = useContext(store);
const { rows, selection } = state;
useEffect(() => {
// apiData().then((data) => {
setRows(data.rows);
// })
// .catch(err => {
// console.log(err);
// })
}, []);
return (
<table>
<thead>
<tr>
<th />
{columns.map((c, idx) => (
<th key={idx}>{c}</th>
))}
</tr>
</thead>
<tbody>
<ExpandableRowTable
showIcon={state.showIcon}
loadData={(id, row) => {
return new Promise(resolve => {
const lastSelection = selection[selection.length - 1];
setTimeout(() => {
resolve(data.options[lastSelection]);
}, 1000);
});
}}
onExpand={(action, id, row) => {
setRows(rows);
toggleIcon();
}}
columns={columns}
rows={rows}
/>
</tbody>
</table>
);
}
export default function App() {
return (
<div>
<StateProvider>
<Select />
<Table />
</StateProvider>
</div>
);
}
解决方案 2 有效 example
import React, { useState, useEffect, useRef, Fragment } from "react";
import axios from "axios";
class TableRowData extends React.Component {
state = {
showIcon: false,
selection: [],
data: []
};
constructor(props) {
super(props);
}
componentDidMount() {
axios.get("https://jsonplaceholder.typicode.com/users").then((res) => {
const rowData = res.data.map((row) => {
row.isExpanded = false;
return row;
});
this.setState({ data: rowData });
});
}
render() {
const updateState = () => {
this.setState(
{
data: [...this.state.data]
},
() => {}
)
}
const ExpandableTableRow = ({ rows }) => {
const expandRow = (row) => {
row.children = [
{
id: "_" + Math.random().toString(36).substr(2, 5),
name: row.id + "_ID1",
isExpanded: false,
parentId: row.id
},
{
id: "_" + Math.random().toString(36).substr(2, 5),
name: row.id + "_ID2ß",
isExpanded: false,
parentId: row.id
}
];
row.isExpanded = true;
updateState();
};
const collapseRow = (row) => {
delete row.children;
row.isExpanded = false;
updateState();
};
const ExpandCollapsToggle = ({ row, expandRow, collapseRow }) => {
return (
<button type="button" onClick={() => row.isExpanded ? collapseRow(row) : expandRow(row)}>
{row.isExpanded ? '-' : '+'}
</button>
);
};
if (rows) {
return rows.map((row) => {
let children = null;
return (
<Fragment key={row.id}>
<tr key={row.id}>
<td>
<ExpandCollapsToggle
row={row}
expandRow={expandRow}
collapseRow={collapseRow}
/>{" "}
{row.id}
</td>
<td>{row.name}</td>
</tr>
<ExpandableTableRow rows={row.children} />
</Fragment>
);
});
return null;
};
if (this.state.data) {
return (
<Fragment>
<ExpandableTableRow rows={this.state.data} />
</Fragment>
);
}
return null;
}
}
const mapStateToProps = (state) => {
return { data: state.reportReducer.data };
};
export default TableRowData;
解决方案 3 有效 example
关于reactjs - 如何使用递归使用react js创建树表?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66239269/
问题是,当用户回复彼此的帖子时,我必须这样做: margin-left:40px; 对于 1 级深度 react margin-left:80px; 对于 2 层深等 但是我想让 react div
我试图弄清楚如何将 React Router 与 React VR 连接起来。 首先,我应该使用 react-router dom/native ?目前尚不清楚,因为 React VR 构建在 Rea
我是 React 或一般编码背景的新手。我不确定这些陈述之间有什么区别 import * as react from 'react' 和 import react from 'react' 提前致谢!
我正在使用最新的稳定版本的 react、react-native、react-test-renderer、react-dom。 然而,react-native 依赖于 react@16.0.0-alp
是否 react 原生 应用程序开发可以通过软件架构实现,例如 MVC、MVP、MVVM ? 谢谢你。 最佳答案 是的。 React Native 只是你提到的那些软件设计模式中的“V”。如果你考虑其
您好我正在尝试在我的导航器右按钮中绑定(bind)一个功能, 但它给出了错误。 这是我的代码: import React, { Component } from 'react'; import Ico
我使用react native创建了一个应用程序,我正在尝试生成apk。在http://facebook.github.io/react-native/docs/signed-apk-android.
1 [我尝试将分页的 z-index 更改为 0,但没有成功] 这是我的codesandbox的链接:请检查最后一个选择下拉列表,它位于分页后面。 https://codesandbox.io/s/j
我注意到 React 可以这样导入: import * as React from 'react'; ...或者像这样: import React from 'react'; 第一个导入 react
我是 react-native 的新手。我正在使用 React Native Paper 为所有屏幕提供主题。我也在使用 react 导航堆栈导航器和抽屉导航器。首先,对于导航,论文主题在导航组件中不
我有一个使用 Ignite CLI 创建的 React Native 应用程序.我正在尝试将 TabNavigator 与 React Navigation 结合使用,但我似乎无法弄清楚如何将数据从一
我正在尝试在我的 React 应用程序中进行快照测试。我已经在使用 react-testing-library 进行一般的单元测试。然而,对于快照测试,我在网上看到了不同的方法,要么使用 react-
我正在使用 react-native 构建跨平台 native 应用程序,并使用 react-navigation 在屏幕之间导航和使用 redux 管理导航状态。当我嵌套导航器时会出现问题。 例如,
由于分页和 React Native Navigation,我面临着一种复杂的问题。 单击具有类别列表的抽屉,它们都将转到屏幕 问题陈述: 当我随机点击类别时,一切正常。但是,在分页过程中遇到问题。假
这是我的抽屉导航: const DashboardStack = StackNavigator({ Dashboard: { screen: Dashboard
尝试构建 react-native android 应用程序但出现以下错误 info Running jetifier to migrate libraries to AndroidX. You ca
我目前正在一个应用程序中实现 React Router v.4,我也在其中使用 Webpack 进行捆绑。在我的 webpack 配置中,我将 React、ReactDOM 和 React-route
我正在使用 React.children 渲染一些带有 react router 的子路由(对于某个主路由下的所有子路由。 这对我来说一直很好,但是我之前正在解构传递给 children 的 Prop
当我运行 React 应用程序时,它显示 export 'React'(导入为 'React')在 'react' 中找不到。所有页面错误 see image here . 最佳答案 根据图像中的错误
当我使用这个例子在我的应用程序上实现 Image-slider 时,我遇到了这个错误。 import React,{Component} from 'react' import {View,T
我是一名优秀的程序员,十分优秀!