上下文:
我希望通过父元素上的onClick触发父级子组件中的事件
代码:
亲本PlantContainer:
import React from "react";
import ClipLoader from "react-spinners/ClipLoader";
import Box from '@material-ui/core/Box';
import ShowMetric from '../showMetric';
export default class PlantContainer extends React.Component {
constructor(props) {
super(props);
this.state = {
isLoading: false,
};
}
render() {
return (
<Box>
<h2>{this.props.plantName}</h2>
<ShowMetric
setting={this.props.plantName + ".moisture"}
unit="%">Moisture:</ShowMetric>
<ShowMetric
setting={this.props.plantName + ".conductivity"}
unit="%">Fertility:</ShowMetric>
</Box>
);
}
}儿童ShowMetric:
import React from "react";
import ClipLoader from "react-spinners/ClipLoader";
import resolvePath from 'object-resolve-path';
export default class ShowMetric extends React.Component {
constructor(props) {
super(props);
this.getData = this.getData.bind(this);
this.state = {
isLoading: false,
reading: 0,
};
}
getData() {
this.setState({ isLoading: true });
fetch(URL_HERE, {
headers: {
"Content-Type": "application/json",
Accept: "application/json",
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Headers": "*",
},
})
.then(function (response) {
return response.json();
})
.then((json) =>
this.setState({
reading: resolvePath(json, this.props.setting),
isLoading: false,
})
);
}
componentDidMount() {
this.getData();
}
render() {
if (this.state.isLoading) {
return <ClipLoader />;
}
return (
<div onClick={this.getData}>
{this.props.children + " "}
<nobr>{`${this.state.reading.toFixed(1)} ${this.props.unit}`}</nobr>
</div>
);
}
}Main App.js:
import './App.css';
import React from 'react';
import Container from '@material-ui/core/Container';
import Box from '@material-ui/core/Box';
import PlantContainer from './components/plantContainer';
function App() {
return (
<div className="App">
<Container maxWidth="md">
<Box className="flexBox">
<PlantContainer plantName="Plant_1"/>
<PlantContainer plantName="Plant_2"/>
</Box>
</Container>
</div>
);
}
export default App;问题
上面的代码与预期的一样工作,因为<ShowMetric/>显示了信息并在我单击它时重新加载。
现在,当我单击PlantContainer的<H2>元素时,我希望重新加载PlantContainer中的所有<H2>元素(可能会触发每个元素的getData()函数)。
我试图寻找如何将事件或信息传递给孩子的方法,但是因为道具在运行时不能改变(?)我不认为引用会是最好的方式,我有点不知道如何实现这一点。
由于这是我的第一个反应网络应用程序和努力到这个框架,请喊出任何可疑的东西,你可以在代码中找到。
发布于 2021-08-29 13:58:26
我认为更优雅的方法是将所有数据存储在父组件中,并通过道具将其传递给子组件。
下面是一个可能的解决方案(我使用函数组件,因为它应该比类组件具有特权):
PlantContainer
function fetchData() {
return fetch(URL_HERE, {
headers: {
"Content-Type": "application/json",
Accept: "application/json",
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Headers": "*",
},
})
.then(response => response.json());
}
export default function PlantContainer(props) {
const [data, setData] = React.useState({
isLoading: false,
'moisture': 0,
'conductivity': 0
});
function loadData() {
setData({...data, isLoading: true});
fetchData().then(json => {
setData({
isLoading: false,
'moisture': resolvePath(json, `${props.plantName}.moisture`),
'conductivity': resolvePath(json, `${props.plantName}.conductivity`)
});
});
}
React.useEffect(loadData, []);
return (
<Box>
<h2 onClick={loadData}>{props.plantName}</h2>
{data.isLoading && <ClipLoader/>}
{!data.isLoading && (
<ShowMetric
reading={data['moisture']}
unit="%">Moisture:</ShowMetric>
<ShowMetric
reading={data['conductivity']}
unit="%">Fertility:</ShowMetric>
)}
</Box>
);
}ShowMetric
export default function ShowMetric(props) {
return (
<div>
{props.children + " "}
<nobr>{`${props.reading.toFixed(1)} ${props.unit}`}</nobr>
</div>
);
}由于您可以通过一次调用服务来检索所有数据,因此只重新加载一个度量似乎是无用的,所以我只提供了通过单击h2元素重新加载两个度量的机会。
发布于 2022-10-12 10:21:30
useImperativeHandle钩子是完美的允许子组件和参考。
完全工作的例子也支持打字稿!:
//Child Component
//Create your ref types here
export type RefHandler = {
pressAlert: () => void;
inputRef: RefObject<HTMLInputElement>;
};
const Child = forwardRef<RefHandler, Props>((props, ref) => {
const submitRef = useRef<HTMLButtonElement>(null);
const inputRef = useRef<HTMLInputElement>(null);
//Initialise your refs here
useImperativeHandle(ref, () => ({
inputRef: inputRef,
pressAlert: () => submitRef?.current?.click()
}));
return (
<div>
<p>Child Component</p>
<input type="text" value="lorem ipsum" ref={inputRef} />
<br />
<button onClick={() => alert("Alert pressed")} ref={submitRef}>
Alert
</button>
</div>
);
});//Parent
export default function Parent() {
const childRef = useRef<RefHandler>(null);
return (
<>
<p>Parent</p>
<button
onClick={() => {
alert(childRef?.current?.inputRef?.current?.value);
}}
>
Read child input
</button>
<button onClick={() => childRef?.current?.pressAlert()}>
Press child button
</button>
<hr />
<Child ref={childRef} />
</>
);
}https://stackoverflow.com/questions/68973166
复制相似问题