I have this component that processes a card and when you click it redirects you to a past route but your OnClick is not working. I wonder if I could be going wrong
function Characters({
characters,
getAllCharacters,
filterCharacters,
}) {
const history = useHistory();
useEffect(() => {
characters.length === 0 && getAllCharacters();
}, [getAllCharacters]);
return (
<Fragment>
<Header />
<Search characters={characters} />
{ inputCharacters !== "" && filterCharacters.length > 0 ? (
<ListContainer>
{filterCharacters.map((characters) => (
<CardItem
onClick={() => {
history.push(`/characters/${characters.id}`, {
params: { characters },
});
}}
key={characters.id}
name={characters.name}
images={
characters.thumbnail.path + "." + characters.thumbnail.extension
}
/>
)}
</ListContainer>
Component CardItem:
export default function CardItem(props) {
return (
<Container url={props.images}>
<Content>
<p>{props.name}</p>
</Content>
</Container>
);
}
Because you are not using onClick in the CardItem. You just update like this:
<p onClick={props.onClick}>{props.name}</p>
If Container or Content support onClick, you cant put onClick={props.onClick} in this component like a prop
Related
I am working in Reactjs. Right now I am getting the current url/hostname. Now I want to use this URL with an if-else condition, which means I just want if url="/"(home page) then the first header should display otherwise second word should display. In other words, I want to know how we can use if-else condition with dynamic variable?
Here is my current code
import { useRouter } from 'next/router'
const Header = () => {
const router = useRouter();
const url =router.asPath;
return (
<>
<div>
//need to use if else condition based on "url" variable
</div>
</>
)
You can use ternary operators there to render based on a condition, like this:
import { useRouter } from 'next/router'
const Header = () => {
const router = useRouter();
const url = router.asPath;
return (
<>
<div>
{url === "something" ? <Foo /> : <Bar />}
</div>
</>
)
}
import { useRouter } from 'next/router'
const Header = () => {
const router = useRouter();
const url = router.asPath;
return (
<>
<div>
{url === "smth" ? <First /> : <Second />}
</div>
</>
)
}
return (
<>
<div>
{url === "smth" && <First />}
{url === "smth" && <Second />}
</div>
</>
)
}
You use both methods
I've made a list of refs for each of my components that is being rendered in a map, I am assigning a ref to a button within EditWebAppTypeForm and am trying to use it within MappedAccordion but it shows undefined? what can I do to make sure ref is set before passing it in the MappedAccordion component?
The information logged in addtoRefs function is correct, it shows -
(2) [button, button]
I've removed a lot of the code so its easier to read.
function Admin() {
const allRefs = useRef([] as any);
allRefs.current = [];
const addtoRefs = (e: any) => {
if (e && !allRefs?.current?.includes(e)) {
allRefs?.current?.push(e);
}
console.log(allRefs.current); <-- Logs correct info
};
return (
<div className="adminContainer">
<Grid container spacing={2}>
<Grid item md={8} xs={12} sm={12}>
<div style={{ width: 725, paddingBottom: 150 }}>
{webAppTypes &&
webAppTypes.map((a: IWebAppType, index: number) => {
return (
<>
<Accordion
key={a.id}
defaultExpanded={a.id === 0 ? true : false}
>
<AccordionDetails>
<EditWebAppTypeForm
key={a.name}
setWebAppTypes={setWebAppTypes}
IWebAppTypeModel={a}
ref={addtoRefs} // <-- returning ref to add to list
/>
<MappedAccordion
waobj={a}
key={a.id}
setWebAppTypes={setWebAppTypes}
editRef={allRefs.current[index]} <-- using ref but showing undefined in MappedAccordion component
/>
</AccordionDetails>
</Accordion>
</>
);
})}
</div>
</Grid>
</Grid>
</div>
);
}
export default Admin;
EditWebAppTypeForm Component -
const EditWebAppTypeForm = (props: any, ref: any) => {
return (
<div className="editWebAppSContainer">
<form onSubmit={handleSubmit(onSubmit)} id="edit-app-form">
<button hidden={true} ref={ref} type="submit" /> // <-- Assiging ref to button
</form>
</div>
);
};
export default forwardRef(EditWebAppTypeForm);
type MappedAccordionProps = {
waobj: IWebAppType;
setWebAppTypes: Dispatch<SetStateAction<IWebAppType[]>>;
editRef: any;
};
function MappedAccordion({
waobj,
setWebAppTypes,
editRef,
}: MappedAccordionProps) {
const onSubmit = (data: FormFields) => {
console.log(editRef); // <-- Logs undefined
};
return (
<div>
<form onSubmit={handleSubmit(onSubmit)} id="environment-form">
</form>
</div>
);
}
export default MappedAccordion;
I would create an extra component WebAppTypeAccordion like this :
function WebAppTypeAccordion({a, setWebAppTypes}) {
const [formEl, setFormEl] = useState(null);
function handleRef(el) {
if (el) {
setFormEl(el)
}
}
return (
<Accordion defaultExpanded={a.id === 0}>
<AccordionDetails>
<EditWebAppTypeForm
setWebAppTypes={setWebAppTypes}
IWebAppTypeModel={a}
ref={handleRef}
/>
<MappedAccordion
waobj={a}
setWebAppTypes={setWebAppTypes}
editRef={formEl}
/>
</AccordionDetails>
</Accordion>
);
}
Then you can update the Admin component :
webAppTypes.map((a: IWebAppType) => (
<WebAppTypeAccordion key={a.id] a={a} setWebAppTypes={setWebAppTypes} />
))
I am trying to make history by pushing on button click
onclick function of the li is not working
as u can see in the code <SuggestionsList/> is in the last return statement its funtions are rendered in const SuggestionsList = (props) => { . The onclick funtion is comimg inside the const SuggestionsList funtion, this is making the onclick funtion not working
i created the exact working in codesand and its working there without any problem i dont get why its not working in my local
enter link description here
function finddoctor(e) {
console.log(e);
history.push(`/detiled/${e} `);
}
const onChange = (event) => {
const value = event.target.value;
setInputValue(value);
setShowResults(false);
const filteredSuggestions = suggestions.filter(
(suggestion) =>
suggestion.firstname
.toString()
.toLowerCase()
.includes(value.toLowerCase()) ||
suggestion.id.toString().toLowerCase().includes(value.toLowerCase())
);
setFilteredSuggestions(filteredSuggestions);
setDisplaySuggestions(true);
};
const onSelectSuggestion = (index) => {
setSelectedSuggestion(index);
setInputValue(filteredSuggestions[index]);
setFilteredSuggestions([]);
setDisplaySuggestions(false);
};
const SuggestionsList = (props) => {
const {
suggestions,
inputValue,
onSelectSuggestion,
displaySuggestions,
selectedSuggestion,
} = props;
if (inputValue && displaySuggestions) {
if (suggestions.length > 0) {
return (
<ul className="suggestions-list" style={styles.ulstyle}>
{suggestions.map((suggestion, index) => {
const isSelected = selectedSuggestion === index;
const classname = `suggestion ${isSelected ? "selected" : ""}`;
return (
<>
<li
style={styles.listyle}
onClick={finddoctor(suggestion.id)}
key={index}
className={classname}
>
{suggestion.firstname}
</li>
</>
);
})}
</ul>
);
} else {
return <div>No suggestions available...</div>;
}
}
return <></>;
};
useEffect(() => {
axios
.get("admin-panel/all-doctors-list/")
.then((res) => {
const data = res.data;
setShowSerch(data);
});
}, []);
return (
<>
<div className="note-container" style={styles.card}>
<div style={styles.inner}>
<p style={{ textAlign: "left" }}>Search Doctors</p>
<form className="search-form" style={{}}>
{showResults ? (
<FontAwesomeIcon
style={{ marginRight: "-23px" }}
icon={faSearch}
/>
) : null}
<input
onChange={onChange}
value={inputValue}
style={styles.input}
type="Search"
/>
<SuggestionsList
inputValue={inputValue}
selectedSuggestion={selectedSuggestion}
onSelectSuggestion={onSelectSuggestion}
displaySuggestions={displaySuggestions}
suggestions={filteredSuggestions}
/>
</form>
</div>
</div>
</>
);
};
Instead of onClick={finddoctor(suggestion.id)} (Here just function invocation is happening and expected to have the callback method)
should be
onClick={() => finddoctor(suggestion.id)}
With my menu I encounter different problem.
For starters, in the first RETURN, I have a TREEITEM with a LISTITEM and a LISTITETEXT.
I put an OnClick in the LISTITETEXT so that if the id of my menu is equal to a value I authorize a redirection.
However, the redirection reloads the page and this is not the purpose of my menu when I use react.
Second, I have my other RETURN which contains my submenu.
it is displayed correctly, when I click on the TREEITEM, I am redirected to the right page.
However, I have the error in the console:
Warning: You tried to redirect to the same route you're currently on:
"/extranetV1/prospect"
{stoMenu && (
<TreeView
style={layout.menu}
defaultCollapseIcon={<ArrowDropDownIcon />}
defaultExpandIcon={<ArrowRightIcon />}
>
{stoMenu.root.children.map(menu => {
return (
<TreeItem
key={menu.nodeId}
nodeId={menu.nodeId}
label={
<ListItem style={layout.menuListItem} className={menu.iconCls}>
<ListItemText style={layout.menuText} primary={menu.text} onClick={() => {
if (menu.id === '/accueil') {
window.location.assign(menu.id);
}
}} />
</ListItem>
}
>
{menu.children.map(child => {
return (
<TreeItem
key={child.nodeId}
nodeId={child.nodeId}
label={child.text}
>
<Redirect to={child.id}/>
</TreeItem>
);
})}
</TreeItem>
);
})}
</TreeView>
)}
For both scenarios you use redirection in react wrong.
You need to use react router for redirection inside react app and instead of window.location.assign(menu.id) it will be props.history.push(menu.id).
I see in the second one you use Redirect component. The problem is that you trigger redirect each time in the loop. You should set some state instead and trigger render with condition earlier in the code.
const MyComponent = (props) => {
const [state, setState] = useState({ pathToRedirect: null });
const handleRedirect = (to) => {
setState({ pathToRedirect: to});
}
render () {
if (state.pathToRedirect) {
return <Redirect to={state.pathToRedirect} />;
}
//render list with handleRedirect onClick
return (...);
}
To correct my problem of reloading the page, I integrated this:
<TreeItem
key={menu.nodeId}
nodeId={menu.nodeId}
label={
<ListItem style={layout.menuListItem} className={menu.iconCls}>
<ListItemText style={layout.menuText} primary={menu.text} onClick={() => {
if (menu.id === '/accueil') {
this.props.history.push(menu.id);
}
}} />
</ListItem>
}
>
I removed the REDIRECT by this in my sub menu :
<TreeItem
key={child.nodeId}
nodeId={child.nodeId}
label={child.text}
onClick={() => {
if (child.id) {
this.props.history.push(child.id);
}
}}
/>
I want to make a page with react components.
For that, I want to separate my code in several parts.
I want to create a page in my Layout function that uses various components like my MenuComponent.
However, I do not understand how to recover my MenuComponent in my Layout.
Thanks for your help.
function Menu () {
const [menuItems, setItems] = useState(null);
useEffect(() => {
getMenuItems().then(setItems);
}, []);
if (!menuItems) {
return null;
}
return (
<div>
{menuItems.data.root.children.map(menu => {
return (
<TreeItem key={menu.id} nodeId="1" label={menu.text} labelIcon={Label}>
{menu.children.map(child => {
return (
<TreeItem key={child.id} nodeId="1" label={child.text} labelIcon={Label}>
{console.log(child.text)}
</TreeItem>
);
})}
</TreeItem>
);
})}
</div>
);
}
export default function Layout() {
const classes = useStyles();
if (!isLogged()) {
return (
<div className="fondLogin" fullscreen>
<SnackbarProvider
maxSnack={1}
anchorOrigin={{
vertical: "top",
horizontal: "center"
}}
>
<Login onSuccess />
</SnackbarProvider>
</div>
);
}
return (
<div className="containerGeneral">
<InactivityManager />
<Menu />
</div>
);
}
Satif is completely right, if you are using a hooks approach, then you should make an async calls into useEffect hook.
Another thing, your component should always return something. If you want to prevent render just return null. In your case you are returning undefined.
function Menu () {
const [menuItems, setItems] = useState(null);
useEffect(() => {
getMenuItems().then(setItems);
}, []);
if (!menuItems) {
return null;
}
return (
<div>
{menuItems.children.map(menu => {
return (
<TreeItem key={menu.id} nodeId="1" label={menu.text} labelIcon={Label}>
</TreeItem>
);
})};
</div>
);
}
The menu component is wrong. You need to fetch a data in useEffect or componentDidMount methods.