I want to call a component and render it once on button click. So if I pressed the button again it would render however does not constantly try and re render itself.
At the moment, I am passing a function to the component and calling at the end of the useEffect. However this seems to not render anything.
Here is what I have in my App.js
function App() {
const [open, setOpen] = React.useState(false);
const [dataFormat, setDataFormat] = React.useState("");
const openData = () => {
setOpen(true);
};
const closeData = () =>{
setOpen(false);
}
const changeDataFormat = (selectedOption) => {
console.log(selectedOption);
setDataFormat(selectedOption);
};
return (
<main className="App">
<h1>Film Management</h1>
<SelectDataFormat changeDataFormat={changeDataFormat} />
<button onClick={openData}>Show Films</button>
<table border="1">
<thead>
<tr>
<th>Title</th>
<th>Year</th>
<th>Director</th>
<th>Stars</th>
<th>Review</th>
</tr>
</thead>
<tbody>{open && <FilmTableRows closeData={closeData} dataFormat={dataFormat} />}</tbody>
</table>
</main>
);
}
And this is the component I want to render
function FilmTableRows(props) {
const convert = require("xml-js");
const dataFormat = props.dataFormat;
const [filmList, setFilmList] = useState([]);
const baseURL = "http://localhost:8080/FilmRestful/filmapi";
const getJson = () => {
let config = {
headers: {
"data-type": "json",
"Content-type": "application/json",
},
};
axios
.get(baseURL, config)
.then((res) => {
const resData = res.data;
setFilmList(resData);
})
.catch((err) => {});
};
const getXML = () => {
let config = {
headers: {
"data-type": "xml",
"Content-type": "application/xml",
// accept: "application/xml",
},
};
axios
.get(baseURL, config)
.then((res) => {
let newList = [];
const resData = JSON.parse(
convert.xml2json(res.data, { compact: true, spaces: 2 })
);
resData.films.film.forEach((f) => {
const film = new Film(
f.id,
f.title,
f.year,
f.director,
f.stars,
f.review
);
newList = newList.concat(film);
});
setFilmList(newList);
})
.catch((err) => {});
};
const getString = () => {
let config = {
headers: {
"data-type": "string",
"Content-type": "application/html",
// accept: "application/xml",
},
};
axios
.get(baseURL, config)
.then((res) => {
setFilmList(res.data);
})
.catch((err) => {});
};
useEffect(() => {
switch (dataFormat.value) {
case "json":
getJson();
break;
case "xml":
getXML();
break;
default:
getString();
}
});
const child = filmList.map((el, index) => {
return (
<tr key={index}>
<td>{el.title}</td>
<td>{el.year}</td>
<td>{el.director}</td>
<td>{el.stars}</td>
<td>{el.review}</td>
</tr>
);
});
return <>{filmList && child}</>;
}
CodePudding user response:
Here is an Example Code
import * as React from 'react';
function App() {
//toggle the state (false by default)
const [toggle, setToggle] = React.useState(false)
//Component to be displayed on button click
const FilmTableRows = () =>{
return(
<div>
<h1>Film</h1>
<p>FilmTableRows</p>
</div>
)
}
return (
<div>
<h1>Hello StackBlitz!</h1>
{/* basically switches the value of toggle on every click */}
<button onClick={() => setToggle(!toggle)}>Click Me</button>
{toggle && <FilmTableRows/>}
</div>
);
}
export default App
CodePudding user response:
Quick fix
const [reload, setReload] = useState(false);
// toggle reload
const refresh = () => {
setReload(r => !r);
};
const openData = () => {
setOpen(true);
// if you want the same button "Show Films" to refersh
if (open) {
refresh();
}
};
return (
...
<button onClick={toggleOpen}>Show Films</button>
// if you want to use seperate refresh button
// <button onClick={refresh}>Refresh</button>
...
<tbody>{open && <FilmTableRows reload={reload} closeData={closeData} dataFormat={dataFormat} />}</tbody>
Inside FilmTableRows use reload to trigger fetch
// include depedency to stop fetching on every render
useEffect(() => {
switch (dataFormat.value) {
case "json":
getJson();
break;
case "xml":
getXML();
break;
default:
getString();
}
}, [dataFormat.value, props.reload]);
Ideally you should move the fetch function in the parent, so that on refresh fetch data can be called from the event handler
You can also use a
filter
state instead ofreload
flag and use the filter as a param when making an api call
Hope it helps you towards finding better solution, you can also read the new React beta docs, they will help you to write better code.
Cheers