首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >React:通过单击父组件在子组件中触发事件

React:通过单击父组件在子组件中触发事件
EN

Stack Overflow用户
提问于 2021-08-29 13:01:48
回答 2查看 2.8K关注 0票数 0

上下文:

我希望通过父元素上的onClick触发父级子组件中的事件

代码:

亲本PlantContainer:

代码语言:javascript
复制
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:

代码语言:javascript
复制
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:

代码语言:javascript
复制
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()函数)。

我试图寻找如何将事件或信息传递给孩子的方法,但是因为道具在运行时不能改变(?)我不认为引用会是最好的方式,我有点不知道如何实现这一点。

由于这是我的第一个反应网络应用程序和努力到这个框架,请喊出任何可疑的东西,你可以在代码中找到。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2021-08-29 13:58:26

我认为更优雅的方法是将所有数据存储在父组件中,并通过道具将其传递给子组件。

下面是一个可能的解决方案(我使用函数组件,因为它应该比类组件具有特权):

PlantContainer

代码语言:javascript
复制
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

代码语言:javascript
复制
export default function ShowMetric(props) {
  return (
    <div>
      {props.children + " "}
      <nobr>{`${props.reading.toFixed(1)} ${props.unit}`}</nobr>
    </div>
  );
}

由于您可以通过一次调用服务来检索所有数据,因此只重新加载一个度量似乎是无用的,所以我只提供了通过单击h2元素重新加载两个度量的机会。

票数 1
EN

Stack Overflow用户

发布于 2022-10-12 10:21:30

useImperativeHandle钩子是完美的允许子组件和参考。

完全工作的例子也支持打字稿!:

代码语言:javascript
复制
//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>
  );
});
代码语言:javascript
复制
//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} />
    </>
  );
}
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/68973166

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档