I have a search form in React that performs an API call and saves the data called nameservers in-state using the useState() React hook.
I'm trying to determine how I can pass this data to another component so the data can be used for rendering elsewhere on the page.
Currently, I'm just outputting the data in my return block which appears below the search form.
import React, { useState } from "react";
import { Spinner, Form, Button, Container, Col } from "react-bootstrap";
import { FaSearch } from "react-icons/fa";
const SearchForm: React.FC = () => {
const [domain, setDomain] = useState("");
const [loading, setLoading] = useState(false);
const [nameservers, setNameservers] = useState([]);
const [submitted, setSubmitted] = useState(false);
const formText = "Search for a domains";
const handleChange = (event: any) => {
setDomain(event.target.value);
};
const handleSubmit = (event: any) => {
event.preventDefault();
setLoading(true);
setSubmitted(true);
console.log(domain);
fetch(`https://dns.google.com/resolve?name=${domain}&type=NS`)
.then(results => results.json())
.then(data => {
setLoading(false);
if (data && data.Answer) {
data.Answer.sort((a: any, b: any) => a.data.localeCompare(b.data));
setNameservers(data.Answer);
}
});
};
return (
<>
<Form onSubmit={handleSubmit}>
<Form.Row>
<Col />
<Col>
<Form.Control
type="text"
placeholder={formText}
value={domain}
onChange={handleChange}
autoFocus
required
/>
</Col>
<Col>
<Button variant="primary" type="submit">
<FaSearch /> Search
</Button>
</Col>
</Form.Row>
</Form>
<hr />
{submitted &&
nameservers.map((server: any, index: number) => (
<li key={index}>{server.data}</li>
))}
{submitted && nameservers.length === 0 && <small>Error</small>}
{loading && (
<Container className="text-center">
<Spinner animation="grow" size="sm" />
<Spinner animation="grow" size="sm" />
<Spinner animation="grow" size="sm" />
</Container>
)}
</>
);
};
export default SearchForm;
There are multiple ways to share data between components. You can use one of the following options:
If the component to which you want to pass the data is a child of SearchForm
component, then you can pass it as a prop
.
If you are managing state via redux, you can connect components to the redux store and get the required data from the redux store in your components.
You can also use React's Context API
to share common data between components that may or may not have a parent-child relationship.
If the component that needs the data from SearchForm
component, is a parent component of SearchForm
component, you can pass a callback function to the SearchForm
component as a prop
and when data is available in SearchForm
component, call the callback function, received as a prop
, and pass the data as an argument to that callback function.
I'd do what Yousaf suggested.
SearchForm should have two props: nameservers handleSubmit
(This will make it easy to write a Storybook story and any tests).
Then make a wrapper for SearchForm that does the API call (handleSubmit) and sets nameservers in context. Now nameservers can be accessed elsewhere in the app.
Ciao, when I want to share data between components I use React-Redux . Lets make an example: Suppose that you want to share data received by server (nameservers). At first install react-redux:
npm install react-redux
npm install redux
npm install @reduxjs/toolkit
Now we have to create the reducer
and the action
: Lets say you have your component in a folder called "/components/MyComponent". Create a file called MyReducer.js.
/components/MyComponent/MyReducer.js
import { createReducer } from '@reduxjs/toolkit';
const initialState = {
nameservers: undefined,
};
const LoginReducer = createReducer(initialState, {
["SET_NAMESERVERS"]: (state, action) => {
state.nameservers= action.payload.nameservers;
},
})
export default MyReducer;
Now, on the same folder, createa file called MyAction.js
/components/MyComponent/MyAction.js
export const setNameServers = data => ({
type: "SET_NAMESERVERS",
payload: { nameservers: data }
});
Then create the store
: On your project root create a folder callled redux
. Inside this create a folder called store
. Then on this folder create a file called index.js.
redux/store/index.js
import { createStore, combineReducers } from "redux";
import MyReducer from '../../components/MyComponent/MyReducer';
const reducers = combineReducers({
MyReducer,
});
const store = createStore(reducers);
export default store;
Now on index.js file on root folder lets pass the store already created:
index.js
...
import { Provider } from 'react-redux';
import store from "./redux/store";
ReactDOM.render((
<Provider store={store}>
<App />
</Provider>
), document.getElementById('root') || document.createElement('div'));
We have almost done. On your component (MyComponent) you retrieve data from server. Once you have data, lets dispatch data to share into the store :
/components/MyComponent/MyComponent.js
...
import { useDispatch } from 'react-redux';
import { setNameServers } from './MyComponentAction';
const MyComponent: React.FC = () => {
const [nameservers, setNameservers] = useState([]);
const dispatch = useDispatch();
....
const handleSubmit = (event: any) => {
...
fetch(`https://dns.google.com/resolve?name=${domain}&type=NS`)
.then(results => results.json())
.then(data => {
setLoading(false);
if (data && data.Answer) {
data.Answer.sort((a: any, b: any) => a.data.localeCompare(b.data));
setNameservers(data.Answer);
dispatch(setNameServers(data.Answer)); // here the magic
}
});
};
};
Done: now you have nameservers on your react redux store and you can easly get it from another component like this:
OtherComponent.js
import { useSelector } from 'react-redux';
const OtherComponent: React.FC = () => {
const nameservers = useSelector(state => state.MyReducer.nameservers);
};
And if you log nameservers somewhere in OtherComponent
you will see data retrieved in MyComponent
. Awesome!
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.