reactjs - ReactJS 和 Typescript - 子组件:在父状态更改时获取子道具并刷新子组件
问题描述
我需要关于 ReactJS 和 Typescript 代码的帮助,使用 material-ui。
我想通过创建自己的组件名称来重做以下链接上建议的选项卡系统:https ://material-ui.com/components/tabs/#simple-tabs 。
这是我制作的代码:https ://codepen.io/Answerrer/pen/wvKLLzg 。
interface MyTabPanelProperties {
label: string;
value: number;
index: number;
children?: React.ReactNode;
}
type MyTabPanelState = {}
class MyTabPanel extends React.Component<MyTabPanelProperties, MyTabPanelState> {
render(): JSX.Element {
const { children, value, index } = this.props;
const element = (
<div role="tabpanel" hidden={value !== index} aria-labelledby={'simple-tab'}>
{children}
</div>
);
return element;
}
}
interface MyTabsProperties<T = MyTabPanelProperties> {
value?: number;
children: React.ReactElement<T> | Array<React.ReactElement<T>> | React.Component<T> | Array<React.Component<T>>;
}
interface MyTabsState {
value: number;
}
class MyTabs extends React.Component<MyTabsProperties, MyTabsState> {
constructor(props: MyTabsProperties) {
super(props);
this.state = {
value: this.props.value ? this.props.value : 0
};
}
private checkChildrenName(children: ReactNode, names: string | Array<string>): boolean {
const childs = React.Children.toArray(children);
let check = false,
allNames = new Array<string>();
if (names instanceof Array) {
allNames = names;
} else {
allNames = names.split(' ');
}
if (allNames.length === 0) {
throw Error('Must specify names for check children');
}
check = childs.every((child) => {
let check = false;
const name = this.getComponentChildName(child);
if (name) {
check = allNames.includes(name);
}
return check;
});
return check;
}
private getComponentChildName(component: any): string | undefined {
const type = (component.type || {});
let name = undefined;
if (component) {
name = component.displayName ||
component.name ||
type.displayName ||
type.name ||
undefined;
}
return name;
}
render(): JSX.Element {
const { children } = this.props;
let element: JSX.Element;
if (this.checkChildrenName(children, 'MyTabPanel')) {
element = (
<div>
<AppBar position='static'>
<Tabs value='0' onChange={this.handleChange.bind(this)}>
{React.Children.map(children, (child, index) => {
return this.renderAppBarTab(child, index);
})}
</Tabs>
</AppBar>
{children}
</div>
);
} else {
throw Error('Must use MyTabPanel component in a MyTabs component');
}
return element;
}
private handleChange(event: React.ChangeEvent<{}>, newValue: number): void {}
private renderAppBarTab(child, index: number): JSX.Element {
const label = 'Test';
const element = (
<Tab label={label} key={index} />
);
return element;
}
set value(value:number) {
this.setState({value: value});
}
}
ReactDOM.render(
<React.StrictMode>
<MyTabs>
<MyTabPanel label='Tab1'>
<Typography>Test1</Typography>
</MyTabPanel>
<MyTabPanel label='Tab2'>
<Typography>Test2</Typography>
</MyTabPanel>
</MyTabs>
</React.StrictMode>
, document.getElementById('root'));
当我的工作站工作正常时,我不知道为什么我不能让它在CodePen上工作。
我的父组件是MyTabset我的子组件是MyTabPanel。
在以下几点上,我需要您的帮助:
- 在我的父组件,renderAppBarTab方法中,我想具体检索我的子组件的属性,标签属性(今天我设置了一个硬常量,因为我不知道该怎么做)?TypeScript 不允许我在我的孩子上调用 props,因为我的孩子参数的类型不适合它。我想检索用于我的子组件 (MyTabPanelProperties) 的类型的属性。
- 我想通过修改父组件的状态(value 属性)来更新子组件的隐藏属性,如 material-ui 提出的示例所示。
有人有想法么?
提前致谢
解决方案
我一直在寻找解决方案并找到了一些东西:https ://codepen.io/Answerrer/pen/ExPxmEN 。
interface MyTabPanelProperties {
label: string;
children?: React.ReactNode;
}
type MyTabPanelState = {}
class MyTabPanel extends React.Component<MyTabPanelProperties, MyTabPanelState> {
render(): JSX.Element {
const { children, value, index } = this.props;
const element = (
<div role="tabpanel" aria-labelledby={'simple-tab'}>
{children}
</div>
);
return element;
}
}
interface MyTabsProperties<T = MyTabPanelProperties> {
selectedTab?: unknown;
children: React.ReactElement<T> | Array<React.ReactElement<T>> | React.Component<T> | Array<React.Component<T>>;
}
interface MyTabsState {
selectedTab?: unknown;
}
class MyTabs extends React.Component<MyTabsProperties, MyTabsState> {
constructor(props: MyTabsProperties) {
super(props);
const { children } = this.props;
const allChilds = React.Children.toArray(children);
let selectedChildId;
if (allChilds.length > 0) {
selectedChildId = (allChilds[0] as MyTabPanel).props.id;
} else {
selectedChildId = 0;
}
this.state = {
selectedTab: this.props.selectedTab ? this.props.selectedTab : selectedChildId
};
}
private checkChildrenName(children: ReactNode, names: string | Array<string>): boolean {
const childs = React.Children.toArray(children);
let check = false,
allNames = new Array<string>();
if (names instanceof Array) {
allNames = names;
} else {
allNames = names.split(' ');
}
if (allNames.length === 0) {
throw Error('Must specify names for check children');
}
check = childs.every((child) => {
let check = false;
const name = this.getComponentChildName(child);
if (name) {
check = allNames.includes(name);
}
return check;
});
return check;
}
private getComponentChildName(component: any): string | undefined {
const type = (component.type || {});
let name = undefined;
if (component) {
name = component.displayName ||
component.name ||
type.displayName ||
type.name ||
undefined;
}
return name;
}
render(): JSX.Element {
const { children } = this.props;
let element: JSX.Element;
if (this.checkChildrenName(children, 'MyTabPanel')) {
element = (
<div>
<AppBar position='static'>
<Tabs value='0' onChange={this.handleChange.bind(this)}>
{React.Children.map(children, (child, index) => {
return this.renderAppBarTab((child as MyTabPanel), index);
})}
</Tabs>
</AppBar>
{React.Children.map(children, (child, index) => {
const id = (child as MyTabPanel).props.id;
if (selectedTab === id) {
return child;
}
})}
</div>
);
} else {
throw Error('Must use MyTabPanel component in a MyTabs component');
}
return element;
}
private handleChange(event: React.ChangeEvent<{}>, selectedTab: unknown): void {
this.selectedTab = selectedTab;
}
set selectedTab(selectedTab: unknown) {
this.setState({ selectedTab: selectedTab });
}
private renderAppBarTab(child:MyTabPanel, index: number): JSX.Element {
const { label, id } = child.props;
const element = (
<Tab label={label} value={id} />
);
return element;
}
}
ReactDOM.render(
<React.StrictMode>
<MyTabs>
<MyTabPanel label='Tab1'>
<Typography>Test1</Typography>
</MyTabPanel>
<MyTabPanel label='Tab2'>
<Typography>Test2</Typography>
</MyTabPanel>
</MyTabs>
</React.StrictMode>
, document.getElementById('root'));
在父级的渲染中,我没有更改子级的状态,而是仅显示要显示的子级(其标识符对应于所选选项卡的那个)。暂时有效。但是,我做了一些我不太喜欢的事情,因为我不明白,我不知道我是否有权这样做(无论如何,我的项目没有编译错误和执行)。我不得不让我的孩子们投产。我不知道我是否有权这样做。有人可以清理我吗?我是否有权像在我的情况下那样为我的孩子投胎?谢谢
推荐阅读
- python - 如何查找列表中的数字是否在列表中两个数字的区间内?
- python-3.x - BeautifulSoup 和 urlopen 没有获取正确的表
- java - Java 中逐步对象更新的替代选项
- python-3.x - 将整数转换为字符串,然后再转换回整数
- python - 用值填充三角形网格中每个形状的想法
- sas - 基于变量记录名称包含的宏
- react-hooks - eslint rule warning useEffect
- javascript - How to remove item array with hasOwnProperty()
- angular - Angular,专注于动态显示的输入
- leaflet - Single marker fails to get rendered if it is not in or close to a cluster