我编写了一个组件,父组件打开子组件中的窗口输入数据进行保存,到树形组件下面进行展示,我在保存的时候一直抛出异常提示找不到这个属性
保存数据的时候父级组件这个方法异常了找不到节点TypeError: Cannot read properties of undefined (reading 'children')
以下是完整代码可以运行
父组件
import React, { useState } from 'react';
import {TreeSelect} from 'antd';
import ProjectComponets from '../ModalForm/ProjectComponets';
import { PlusCircleOutlined } from '@ant-design/icons';
import FormComponets from '../ModalForm/FormComponets';
const { SHOW_PARENT } = TreeSelect;
function TreeComponets(){
const [value, setValue] = useState(['0-0-0']);
const [treeData,setData] = useState([]); // 初始化树形数据
const [searchValue, setSearchValue] = useState('');
const [selectedNode, setSelectedNode] = useState(null);
const [isModalOpenForm,setIsModalOpenForm]=useState(false);
const [FormSelectedNode,setFormSelectedNode]=useState(null);
const onChange = function (newValue) {
setValue(newValue);
};
const onSearch = (searchText) => {
setSearchValue(searchText);
};
const tProps = {
treeData,
value,
onChange,
treeCheckable: true,
showCheckedStrategy: SHOW_PARENT,
placeholder: 'Please select',
style: {
width: '100%',
},
filterTreeNode: (node) => {
return node.title.toLowerCase().includes(searchValue.toLowerCase());
},
treeDefaultExpandAll: true,
onSearch: onSearch,
onSelect: (selectedValue, node) => {
setSelectedNode(node);
},
};
//接收项目组件传递的数据
const handleSave=(formData)=>{
debugger
// setData([...treeData, formData]); // 将表单数据添加到数组中
const randomId = `SL-${Math.floor(Math.random() * 1000000)}`;
const newNode = {
title: `${formData.newNodeNo}-${formData.newNodeName}`,
value: randomId,
children: [
{ title: `${formData.newNodeNo}-${formData.newNodePName} `, value: `${randomId}-1` },
{ title: <PlusCircleOutlined onClick={showModalForm} /> , value: `${randomId}-2` }
],
};
const newData = [...treeData];
if (!selectedNode) {
newData.push(newNode);
} else {
selectedNode.children.push(newNode);
}
setData(newData);
}
const onSelect = (value, node) => {
debugger
console.log('onSelect', value, node);
setSelectedNode(node);
};
const showModalForm=()=>{
setIsModalOpenForm(true);
setFormSelectedNode(selectedNode); // 将选中的节点信息保存到状态中
};
const handleCloseModal=()=>{
setIsModalOpenForm(false);
};
const FormSave = (data, selectedNode) => {
debugger
const randomId = `SL-${Math.floor(Math.random() * 1000000)}`;
const newNode = {
title: data.FormName,
value: randomId
};
const newData = [...treeData];
selectedNode.children.push(newNode);
setData(newData);
};
return(
<div>
<ProjectComponets onSave={handleSave} />
<TreeSelect {...tProps} onSelect={onSelect} />
<FormComponets visible={isModalOpenForm} onClose={handleCloseModal} onSave={FormSave} />
</div>
);
;
}
export default TreeComponets;
子组件
import React, { useState } from 'react';
import { Button,Modal,Input,Select,Form,Checkbox} from 'antd';
function FormComponets({ visible, onClose,onSave }){
const plainOptions = ['button', 'Lable', 'combox'];
const options = [
{ label: 'Grid', value: 'Apple' },
{ label: 'Tab', value: 'Pear' },
{ label: 'Listview', value: 'Orange' },
];
const [checkedList, setCheckedList] = useState([...plainOptions, ...options.map((option) => option.value)]);
const [indeterminate, setIndeterminate] = useState(true);
const [checkAll, setCheckAll] = useState(false);
const [form] = Form.useForm();//Form.useForm()生成了一个form实例,并将其绑定到了Form组件上
const onCheckAllChange = (e) => {
setCheckedList(e.target.checked ? [...plainOptions, ...options.map((option) => option.value)] : []);
setIndeterminate(false);
setCheckAll(e.target.checked);
};
const onCheckReverseChange = () => {
const newCheckedList = [];
[...plainOptions, ...options.map((option) => option.value)].forEach((value) => {
if (!checkedList.includes(value)) {
newCheckedList.push(value);
}
});
setCheckedList(newCheckedList);
setIndeterminate(!!newCheckedList.length && newCheckedList.length < plainOptions.length + options.length);
setCheckAll(newCheckedList.length === plainOptions.length + options.length);
};
const onChange = (checkedValues) => {
setCheckedList(checkedValues);
setIndeterminate(!!checkedValues.length && checkedValues.length < plainOptions.length + options.length);
setCheckAll(checkedValues.length === plainOptions.length + options.length);
};
const onFinish = (values) => {
onSave(values); // 将表单数据传递给父组件进行保存
visible(false); // 关闭Modal
form.resetFields(); //清空表单数据
};
return (
<div>
<Modal title="定义窗体信息" visible={visible} onCancel={onClose} footer={null}>
<Form
onFinish={onFinish}
>
<Form.Item
label="form name"
name="FormName"
rules={[{ required: true, message: 'Please enter the scheme name!' }]}
>
<Input type="text" style={{ width: '80%' }} placeholder="Please enter the form name" />
</Form.Item>
<Form.Item
label="object name"
name="ObjectName"
rules={[{ required: true, message: 'Please enter the object name!' }]}
>
<Input type="text" style={{ width: '80%' }} placeholder="Please enter the form name" />
</Form.Item>
<Form.Item
label="English name"
name="EnglishName"
rules={[{ required: true, message: 'Please enter the Eeglish name!' }]}
>
<Input type="text" style={{ width: '80%' }} placeholder="Please enter the form name" />
</Form.Item>
{/* 选择框区域 */}
<Form.Item>
<>
<Checkbox.Group options={plainOptions.concat(options)} value={checkedList} onChange={onChange} />
<br />
<br />
<Checkbox
indeterminate={indeterminate}
onChange={onCheckAllChange}
checked={checkAll}
disabled={checkedList.length === 0}
>
全选
</Checkbox>
<Checkbox
style={{ marginLeft: '10px' }}
onClick={onCheckReverseChange}
>
反选
</Checkbox>
</>
</Form.Item>
<Form.Item wrapperCol={{ offset: 18, span: 16 }}>
<Button type="primary" htmlType="submit" >
Submit
</Button>
</Form.Item>
</Form>
</Modal>
</div>
);
}export default FormComponets
这个 selectedNode.children.push(newNode);一直异常
说明 selectedNode 没有children属性 你打印一下看看selectedNode.children.push(newNode); 的上面打印 或者 你加个判断
if (selectedNode.children) {
selectedNode.children.push(newNode);
}
第一步其实我们已经添加过点击事件了:
onClick={()=>scrollToAnchor("page-top", true)}
下面是点击事件的代码示例:
/**
* anchorName: 滑动的目标位置的id
* smooth: 滑动时是否有过渡动画效果
*/
const scrollToAnchor = (anchorName:string, smooth: boolean) => {
if (anchorName) {
const anchorElement = document.getElementById(anchorName);
if (anchorElement) {
anchorElement.scrollIntoView({block: 'start', behavior: smooth? 'smooth': 'auto'});
}
}
}
这样功能就完成了。如果想跳转到页面其他指定位置,也可以按照这样的实现,只要把顶部的锚点div移动到指定位置即可。
解决方案: 针对传递数据并保存到树形节点这个问题,可以采用React中的状态管理工具(如Redux)来实现。在父组件中定义状态,然后将该状态以props的形式传递给子组件,子组件中修改该状态以实现数据传递和保存到树形节点中。
针对抛出异常提示找不到该属性的问题,可能是因为该属性不存在或者该属性在子组件中的命名与在父组件中的命名不一致,需要检查并解决这些问题。另外,这也可能与组件没有正确绑定this有关,可以采用箭头函数或者使用bind来绑定this。
针对简化事件处理程序并避免沟通问题,可以采用函数式组件来实现,避免this的使用以及命名冲突等问题。
针对页面之间的跳转和参数传递,可以采用React Router来实现,通过路由实现页面之间的跳转并将参数以props或者query string的形式传递。
针对评论demo中的优化问题,可以将评论组件拆分成多个较小的组件,使每个组件的职责更加单一,同时也更容易实现组件的复用和样式修改。
针对采用声明式而非命令式的方法,可以采用函数式编程的思想,将函数定义为一系列纯函数的组合,使代码更加简洁、易于维护和重用。
针对评论表和用户表的关联和是否登陆的问题,可以在登录时获取用户的信息并保存到本地存储中,在进行点赞和举报操作时检查用户是否已登陆,再根据用户信息向后台发送请求。如果用户未登录,则无法进行点赞和举报操作。此外,针对ipv6的情况,可以采用ip+user agent的方式来进行用户的唯一标识。