Как передать ответ API от дочернего компонента другому вложенному компоненту? - PullRequest
0 голосов
/ 05 августа 2020

У меня есть компонент MockTable, в котором я получаю ответ API и сохраняю его в переменной data. Я хочу использовать данные в другом компоненте UsecasePane. Могу ли я узнать правильный способ передачи данных в UsecasePane?

  • MockTable - дочерний компонент MainContent.
  • AddMock - дочерний компонент MainContent.

=> MainContent. js

const MainContent = () => {
  return (
    <div >
      <CustomerTable />
      <AddMock />
      <MockTable />
    </div>
  );
};

export default MainContent;

Теперь TabContent является потомком AddMock

=> AddMock. js

const AddMock = () => {
  return (
    <div className="row">
              <Container className="mockbody">
                <Header as="h3">Hierarchy</Header>
                <TabContent />
              </Container>
    </div>
  );
};

export default AddMock;

UsecasePane вложено в TabContent.

// TabContent. js

import React from "react";
import { Tab } from "semantic-ui-react";
import UsecasePane from "./UsecasePane";

const panes = [
  {
    menuItem: "Usecase",
    render: () => <Tab.Pane attached={false}>{<UsecasePane />}</Tab.Pane>,
  }
];

const TabContent = () => (
  <Tab menu={{ secondary: true, pointing: true }} panes={panes} />
);

export default TabContent;

=> MockTable. js

import React, { useState, useEffect } from "react";
import "../assets/css/material-dashboard.css";
import axios from "axios";
import { Icon, Dimmer, Loader, Segment } from "semantic-ui-react";

let config = require("../appConfiguration");

const MockTable = () => {
  const [data, setData] = useState([]);
  const [loading, setLoading] = useState(false);

  const fetchData = async () => {
    const response = await axios
      .get(config.App_URL.getAllTest, {
        params: {
          customHostName: "suite",
          type: "routes",
        },
      })
      .catch((error) => {
        console.error(`Error in fetching the data ${error}`);
      });
    let list = [response.data];
    setData(list);
    setLoading(true);
  };

  useEffect(() => {
    fetchData();
  }, []);

  
return (
     // rest of the code
)
  
};
export default MockTable;

Теперь мне нужно передать эти данные в UsecasePane, который вложен в другой компонент TabContent

Ответы [ 3 ]

2 голосов
/ 05 августа 2020

Существует несколько способов передачи данных дочерним компонентам.

  1. Использование свойств

//In Grandparent
<Parent dataToParent={someData}/>

//In Parent 
<Child dataToChild={props.dataToParent}/>

//Using in Child
render(){
   {props.dataToChild}
}
Рендеринг реквизита (пропуск иерархии)

https://reactjs.org/docs/render-props.html

//In Grandparent component
<Parent dataToParent={dataFromParent => (
  <Child>{dataFromParent}</Child>
)}/>
Хранение данных в центральном состоянии

Контекстный API: https://reactjs.org/docs/context.html

Сторонние библиотеки:

т.е. Redux https://redux.js.org/

Изменить:

Спасибо за обновление вопроса. Глядя на иерархию, кажется, что вы имеете дело с родственными компонентами. т.е. MainContent -> MockTable - это место, где вы извлекаете данные, а MainContent -> AddMock -> TabContent -> UsecasePane - это место, где вы хотите отображать / передавать данные. Для обоих из них непосредственным общим родителем является MainContent.

Если вы не хотите использовать ContextAPI или любую другую стороннюю библиотеку. Я бы предложил поднять ваши состояния до MainContent и передать функцию обратного вызова MockTable и передать состояние MainContent -> AddMock -> TabContent -> UsecasePane

Рассмотрим следующий пример:

//MainContent.js
const MainContent = () => {
  ...
  const [data, setData] = useState([]);
  ...
  return (
    <div >
      <CustomerTable />
      <AddMock setData={setData} /> {/*Passing callback function*/}
      <MockTable data={data} /> {/*Passing state*/}
    </div>
  );
};

export default MainContent;
//AddMock.js
...
const fetchData = async () => {
    // all data fetching logic remains the same.
    let list = [response.data];
    props.setData(list); //Calling callback function to set the state defined in MainContent.js
  };

useEffect(() => {
    fetchData();
  }, []);
...
//AddMock.js

const AddMock = ({data}) => {
  return (
    <div className="row">
              <Container className="mockbody">
                <Header as="h3">Hierarchy</Header>
                <TabContent data={data} /> {/*Passing data props*/}
              </Container>
    </div>
  );
};

export default AddMock;

//TabContent.js

const TabContent = ({data}) => {
const panes = [
  {
    menuItem: "Usecase",
    render: () => <Tab.Pane attached={false}>{<UsecasePane data={data} />}</Tab.Pane>,
  }
];
 return(
  <Tab menu={{ secondary: true, pointing: true }} panes={panes} />
 )
}

export default TabContent;
//

Здесь вы можете видеть, что для передачи данных происходит некоторая prop drilling, хотя это не антипаттерн, но мы бы рекомендовали избегать как можно большего количества специальных компонентов в функциональных компонентах, поскольку они этого не делают. t имеют поддержку shouldComponentUpdate() или React.PureComponent, в противном случае вы можете использовать React.memo HO C Подробнее .

Конечно, React.Context или сторонние библиотеки, то есть Redux (хотя это будет излишне для небольших приложений) есть несколько альтернатив всем этим.

1 голос
/ 05 августа 2020

Отредактировано

Попытайтесь получить свои данные в MainContent, чтобы централизовать ваши данные, а затем отправить их. Используйте обратный вызов (addData), чтобы передать новые данные вашему родительскому объекту

MainContent

const MainContent = () => {
    // get datas

    function addData(newData){
        setData([...data, newData])
    }

    return (
      <div>
        <CustomerTable />
        <AddMock addData={addData} />
        <MockTable data={data} />
      </div>
    );
};

AddMock

const AddMock = (props) => {
    // use props.addData(newData)
};
0 голосов
/ 05 августа 2020

Вы можете создать функцию, которая будет возвращать ваш массив, а затем вы можете передать аргумент этой функции, который будет использоваться в компоненте usecasepane.

const panes = (arg) => {
// do something with arg...
return [
  {
    menuItem: "Usecase",
    render: () => <Tab.Pane attached={false}>{<UsecasePane arg={arg} />}</Tab.Pane>,
  }
];
}

const TabContent = () => (
  <Tab menu={{ secondary: true, pointing: true }} panes={ panes() } />
);
...