My components are not being rendered when I click a link that should load them - reactjs

I'm confused as to why nothing happens when I'm clicking links in my app.
In my index.js file, I am loading my main screen called 'Game'. Inside 'Game', I have two links, that when clicked, should render another screen.
In my index.js:
import React from "react";
import ReactDOM from "react-dom";
import Game from "./Game/Game";
ReactDOM.render(
<React.Fragment>
<Game/>
</React.Fragment>,
document.getElementById('gameContainer')
)
In my index.html:
<div>
<div id="gameContainer"></div>
</div>
<div id="root"></div>
My Game.js:
import React from "react";
import CharacterStats from "../CharacterStats";
import DungeonStats from "../DungeonStats";
const characterStatsComponent = () => {
return (
<CharacterStats />
);
}
const dungeonStatsComponent = () => {
return (
<DungeonStats />
);
}
const Game = () => (
<div>
<a id="showCharacter" href="#" onClick={characterStatsComponent}>Show your character</a>
</div>
<br />
<div>
<a id="showDungeon" href="#" onClick={dungeonStatsComponent}>Show current dungeon</a>
</div>
);
export default Game;
The two other components, CharacterStats and DungeonStats are just a few bits of html and reactjs to show some data.
Neither CharacterStats or DungeonStats are loading when I'm clicking the links.
I am also getting no errors in the console.
Nothing happens when the links are clicked.
I also put this inside each onClick event:
console.log('link was clicked');
And it does show the message in the console. So that shows that it knows the link is being clicked.
Is there anything that would prevent them from being loaded?
Thanks!

It wont work because you are returning jsx into the onClick function context, and not into the Game component's return value.
You could define a state using useState, something like showDungeon and showCharacter that defaults to false, change it to true onClick, and in the Game component's return value add:
{ showDungeon && <DungeonStats /> }

React uses something called Synthetic Events to achieve cross browser event handling. If I understood your question correctly than changing the onclick to onClick should do the job for you.

Related

How can i unmount a functional component from DOM on click of a Button

I would like to "Unmount a simple Functional Component" from the DOM. I searched a lot and saw most of the tutorials are based on Class Components and I did'nt see any simple example on it. My requirement is Unmounting a Functional component from the DOM on click on a button. Following is the component with the button which i likes to unmount when click on it. Hopes someone can help me to do it. Thanks in Advance !
import React from 'react'
function App() {
return (
<div className='app-component'>
<h2 className="h2">App Component</h2>
<button>Unmount This Component</button>
</div>
)
}
export default App
If you want to unmount a component then you can use conditional rendering where you can declare state in parent component and based on the state you can mount or unmount component as:
This is the parent component from where you want to mount or unmount
CODESANDBOX DEMO
If you want to toggle component once then you can do the following because there is only one way to change state i.e from Test component. If you unmount this component there is no way to mount it again. So you can also declare button in App component from where you can mount or unmount on click of a button. CODESANDBOX
Parent component
export default function App() {
const [isShowing, setIsShowing] = useState(true); // STATE
return (
<div className="App">
{isShowing && <Test setIsShowing={setIsShowing} />}
</div>
);
}
Child component
function Test({ setIsShowing }) {
function unmountComponent() {
setIsShowing(false);
}
return (
<div className="app-component">
<h2 className="h2">App Component</h2>
<button onClick={unmountComponent}>Unmount This Component</button>
</div>
);
}
You can use state flag for removing element like this:
import React from 'react'
function App() {
const [flag,setFlage]=useState(true);
return (
<div className='app-component'>
{flag?<h2 className="h2">App Component</h2>:null}
<button onClick={()=>setFlag(!flage)} >Unmount This Component</button>
</div>
)
}
export default App

React tailwind, cannot pass tailwind css from parent to child

I am running into a simple issue that doesn't seem to have an answer on quick google search or Tailwind doc.
I am a Vuejs user but I have started learning React. I have opted to use TailwindCSS for testing my React application but I noticed there is some differences of Tailwind usage between Vuejs and React.
In Vue, I can control a child component via the parent component like so:
Parent component:
<template>
<div class="w-screen">
<ChildComponent class="w-1/2 mx-auto" />
</div>
</template>
With the child being able to centre on screen through the above parent component as should in the ChildComponent's class.
However, when I tried to do the same in React like so:
Parent component:
import Homepage from './views/Homepage';
function App() {
return (
<div className='bg-black w-screen'>
<Homepage className="w-1/2 mx-auto"/>
</div>
);
}
export default App;
Nothin happens when I placed the CSS at the Homepage child component from the parent.
I am sure there is a simple answer but I wasn't about to search the doc or use any keywords to find this problem. Anyone got a hint or confirm this is intended in React or have I done something wrong with the installation?
This is less of a Tailwind question and more of a React question. You cannot use className on the Homepage component without passing it as a prop. In your case, Homepage is not expecting any className. So while making your Homepage component you have to provide a prop called 'className' then it will work fine.
Or if you simply use a div in place of Homepage it will work normally. Have a look at this codesandbox link
You need to consider that <Homepage/> is a React component and cannot accept HTMLAttrs just like that.
this example might clear it:
const app = () => {
<div className="bg-black">
<Homepage className="bg-red" />
</div>
}
const homePage = (props) => {
<div className={props.className}>
<h1 className="bg-red">hi</h1>
</div>
}
the className that you pass to <Homepage/> is actually a props rather than Html attribure.
In Vue it's fairly straightforward but in react you need to be explicit and use className in your component
// Creating component
const Button = ({ className, children }) => {
return <button className={`${className} bg-red-500`}>{children}</button>
}
export default Button
// Using component
<Button className="text-white">MyButton</Button>
import Homepage from './views/Homepage';
function App() {
return (
<div className='bg-black w-screen'>
<Homepage className="w-1/2 mx-auto"/>
</div>
);
}
export default App;
views/Homepage
you have to receive props that are going to be passed as className
const homePage = ({className}) => {
<div className={className}>
<h1 className="bg-red">hi</h1>
</div>
}
export default homePage
then export your component

Any way to open a modal dialog without explicitly storing state?

I have been using react-modal recently, and the pattern to show a modal is something like:
const [modalIsOpen, setModalIsOpen] = useState(false);
return (<ModalDialog isOpen={modalIsOpen}><div>some content</div></ModalDialog>)
...which feels very React-y, but overly verbose. Is there a way to enable something where I can - within a click handler - simply call:
showModal(MyComponent)
and have the state be handled automatically? I've thought about creating a Context around the app that allows showModal to grab state associated with MyComponent, in which case this would itself be a hook, so it would have to follow certain rules (i.e., no conditional calling), so I'm not sure I could make it work as cleanly as I'd like.
Is there a way to do this within the React ecosystem? Or should I just give up and use the existing mechanism?
Yes! You can do it by using the "render" function.
Unfortunately it doesn't work in CodeSandBox, but you can fork it from here:
https://github.com/BHVampire/modal
You close the modal by clicking outside.
This is how I did it:
At the end you'll be able to open a modal like this from any part of your application:
createModal(<h1>Success</h1>)
First, you add a container for your modals outside the App component, so you'll never have problems with the z-index:
index.js
import React from 'react'
import ReactDOM from 'react-dom'
import './index.scss'
import App from './App.jsx'
ReactDOM.render(
<React.StrictMode>
<div id="modal-container"></div> <- This is the container
<App />
</React.StrictMode>,
document.getElementById('root')
)
app.jsx
import createModal from "./components/Modal"
const App = () => {
return <button onClick={() => createModal(<h1>Success</h1>)}>Open Modal</button>
}
export default App
Then I have 2 main files for the modal inside a Modal folder + the style.
Modal/index.js
The state hook is unavoidable for the modal, but you'll never see it again.
import { Fragment, useState } from 'react'
import './Modal.scss'
const Modal = ({ content }) => {
const [isOpen, setIsOpen] = useState(true)
return isOpen
? <Fragment>
<div onClick={() => setIsOpen(false)} className="modal-background" />
<div className="modal" >
{content}
</div>
</Fragment>
: ''
}
export default Modal

onClick not working in form element in react, but works in button?

Trying to get an onClick function working in react with a form , however, it isnt working but using a button does.
The following code works with the button but not the input. I'm wondering what I might be
<CustomInput
onChange={(v) => setLastName(v)}
label="Last Name*"
invalid={
(lastName || validate) &&
!yup.string().required().isValidSync(lastName)
}
value={lastName}
onClick={() => alert('hello')}
/>
<button onClick={() => alert('hello')}>Click me!</button>
This is probably happening because you didn't use the onClick prop anywhere inside CustomComponent. When you passed the onClick prop to the button, React knows that it has to create a button and attach an onclick event listener to it which fires off your alert when the button is clicked. However, when you pass the onClick prop to CustomComponent, since React innately doesn't know what CustomComponent is, it doesn't create a component immediately. It first accesses your CustomComponent's source file, and creates DOM elements according to CustomComponent's render method's return.
Any props that were passed to CustomComponent can be accessed it. When passing props in this manner, React assumes that onClick is just another name for a prop, and doesn't understand that you want it to attach an eventListener to the wrapper element in the return statement of CustomComponent's render method. You will have to manually attach this inside CustomComponent.
for example,
CustomButton.js
import React from 'react';
const CustomButton = props => {
return (
<div>
<button>Click me</button>
</div>
);
};
export default CustomButton;
App.js
import './App.css';
import CustomButton from './CustomButton';
function App() {
return (
<div className="App">
<CustomButton onClick={()=>alert("Clicked")}/>
</div>
);
}
export default App;
In the above case, nothing happens when button is clicked, because there is no onClick in CustomButton.js
However, if this is done:
CustomButton.js
import React from 'react';
const CustomButton = props => {
return (
<div onClick={props.onClick}>
<button>Click me</button>
</div>
);
};
export default CustomButton;
Now, the alert will appear when the button is clicked(or rather, when the div is clicked).
The name of the prop passed to CustomButton needn't have been onClick either, as the word has no significance when used on a custom component.
App.js
import './App.css';
import CustomButton from './CustomButton';
function App() {
return (
<div className="App">
<CustomButton anyprop={()=>alert("Clicked")}/>
</div>
);
}
export default App;
CustomButton.js
import React from 'react';
const CustomButton = props => {
return (
<div>
<button onClick={props.anyprop}>Click me</button>
</div>
);
};
export default CustomButton;
This works just fine as well, so long as the names of the prop being passed in CustomButton and App match.

React Hooks Calling GET Request On Modal Popup

Thanks in advance for any help you can provide. I am trying to create a Modal is react and call a get request to load details of a task.
I have most of it working (I think), but essentially what I have done is createa custom Modal Hook that toggles two modals.
The second of the two modals is meant to open a task and render the task details in a form for editing but I am unable to get it working.
Here is the useModal hook:
import { useState } from "react";
const useModal = () => {
const [isShowing, setIsShowing] = useState(false);
const [secondModalIsShowing, secondModalSetIsShowing] = useState(false);
function toggle() {
setIsShowing(!isShowing);
}
function secondToggle() {
secondModalSetIsShowing(!secondModalIsShowing);
console.log("clicked");
}
return {
isShowing,
toggle,
secondModalIsShowing,
secondToggle,
};
};
export default useModal;
I then call the function for the secondToggle which fires the code below to render the modal. Now as you may see I have to comment out the section where it calls getTask() with match.params.id, as well as the component that is then meant to be rendered in the modal.
If I don't do that I get an error message with the following " Line 23:5: Expected an assignment or function call and instead saw an expression no-unused-expressions"
import React, { Fragment, useEffect, useState } from "react";
import { connect } from "react-redux";
import PropTypes from "prop-types";
import TaskItem from "../tasks/task-item/TaskItem";
import { getTask } from "../../actions/task";
import ReactDOM from "react-dom";
import "./Modal.styles.scss";
import "../dashboard/Dashboard.styles.scss";
import Task from "../task/Task";
import TaskEdit from "../task/TaskEdit";
const TaskModal = ({
getTask,
task: { task, loading },
match,
secondModalIsShowing,
hide,
}) => {
const [displayEdit, toggleDisplayEdit] = useState(false);
useEffect(() => {
getTask();
// match.params.id;
}, [getTask]);
return secondModalIsShowing
? ReactDOM.createPortal(
<React.Fragment>
<button
type="submit"
value="toggle"
onClick={() => toggleDisplayEdit(!displayEdit)}
>
Show/Edit
</button>
{(displayEdit && <TaskItem task={task} />) || (
<div>{/* <TaskEdit /> */}</div>
)}
<div className="modal-overlay" />
<div
className="modal-wrapper"
aria-modal
aria-hidden
tabIndex={-1}
role="dialog"
>
<div className="modal">
<div className="modal-header">
Add New Task
<button
type="button"
className="modal-header__button"
data-dismiss="modal"
aria-label="Close"
onClick={hide}
>
<span aria-hidden="true">×</span>
</button>
</div>
</div>
</div>
</React.Fragment>,
document.body
)
: null;
};
Now if I render this EditTask component outside the modal as a normal component it works correctly. I can also get the modal to render when it's not trying to display the EditTask component.
As a result, I think it's related to the Route path and passing the response to the TaskModal component? When I click the modal to open I cant get it to render the URL with the task ID and therefore I cant render the details of the task in the modal.
<Route path="/taskedit/:id" component={TaskModal} />
For context, I think this guide comes close to solving my issue (https://blog.logrocket.com/building-a-modal-module-for-react-with-react-router/) but I am not familiar with working with class-based components and when I try and convert to functional-based components I'm running into even more issues.
Thanks in advance for any insight you can provide as I keep trying to work through this.
Paul
The first issue I am seeing is you have to pass the task id to TaskModal component
<Route path="/taskedit/:id"
render={(props) => <TaskModal {...props} />}>
</Route>
This will make the task id available as property in TaskModal.
Then in the TaskModal, fetch like below
let taskid = prop.match.params.id;

Resources