Function does not re-render when clicking button - javascript

I am making a simple react counter, where on click INC button the value should change the value inside h1. But it is not working.
My code in App.js:
import React from "react";
import "./styles.css";
export default function App() {
let count = 0;
function handleInc () {
return count++;
}
return (
<>
<div>
<h1>{count}</h1>
<div className='container'>
<button onClick={handleInc}>INC</button>
<button>DEC</button>
<button>RESET</button>
</div>
</div>
</>
);
}
Can you please tell me what the error is?

You need to useState! On each click, this method will tell react to re-render this component and any children, thus displaying the updated counter to the dom.
import React, { useState } from "react";
import "./styles.css";
export default function App() {
let [count, setCount] = useState(0);
function handleInc () {
return setCount(count + 1);
}
return (
<>
<div>
<h1>{count}</h1>
<div className='container'>
<button onClick={handleInc}>INC</button>
<button>DEC</button>
<button>RESET</button>
</div>
</div>
</>
);
}

Related

React JS Page When adding component - but no errors?

When I add my Navigation component to my App.js file the entire site is blank. However, when I add my other components like my Header the page works completely fine. Am I missing something? There are no bugs or errors that are showing up either which is very confusing.
import { useState } from 'react'
import Navigation from './components/Navigation'
import Header from './components/Header';
import Collection from './components/Collection';
function App() {
const [count, setCount] = useState(0)
return (
<div>
<Navigation />
<Header />
<Collection />
</div>
)
}
export default App
import { useState } from "react";
import logo from "../icons/logo.svg";
import CSS from "../styles/Navigation.css";
import hamburger from "../icons/icon-hamburger.svg";
import hamburgerClose from "../icons/icon-close.svg";
import { MobileMenu } from "../components/MobileMenu";
function navigation() {
state = { clicked: false }
handleClick = () => {
this.setState({ clicked: !this.state.clicked })
}
return (
<>
<div className="navigation">
<img className="logo" src={logo} />
<button className="hamburger" onClick={this.handleClick}>
<img className={this.state.clicked ? {hamburger} : {hamburgerClose}}/>
</button>
<div className="navigation-menu">
<ul>
{MobileMenu.map((item, index) => {
return (
<li key={index}>
<a className={item.className} href={item.url}>
{item.title}
</a>
</li>
);
})}
</ul>
</div>
</div>
</>
);
}
export default navigation;
The state could only be used in class components. Using hooks, you can apply state to functional components too. Below code example
import React, { useState } from 'react';
function Example() {
// Declare a new state variable, which we'll call "count"
const [count, setCount] = useState(0);
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>
Click me
</button>
</div>
);
}

React components spams read on firebase collection

So recently i tried making a chat app using React and firebase, to learn these tools. It goes very well, but for some reason it seems that whenever the database is active it spams read on the collection, even with no changes. I suspect some element is rerendering in an infinite loop, but i can't seem to fix it. Any suggestions for how i can display messages and only update whenever a new change is made to the collection?
import React, { useRef, useState } from 'react';
import firebase from 'firebase/compat/app';
import 'firebase/compat/auth';
import 'firebase/compat/firestore';
import { useAuthState } from 'react-firebase-hooks/auth';
import { useCollectionData } from 'react-firebase-hooks/firestore';
import './App.css';
import Navbar from './Navbar';
firebase.initializeApp({
// My configs are here
})
const auth = firebase.auth();
const firestore = firebase.firestore();
function App() {
const [user] = useAuthState(auth);
return (
<>
<div className="App">
<Navbar />
</div>
<section className="place-content-end">
{user ? <ChatRoom /> : <SignIn />}
<SignOut />
</section>
</>
);
}
function SignIn() {
const signInWithGoogle = () => {
const provider = new firebase.auth.GoogleAuthProvider();
auth.signInWithPopup(provider);
}
return (
<>
<button className="sign-in ml-20 pl-5" onClick={signInWithGoogle}>Sign in with Google to join! </button>
<p className="ml-20 pl-5">Welcome to the chat!</p>
</>
)
}
function SignOut() {
return auth.currentUser && (
<button className="sign-out ml-20 pl-5" onClick={() => auth.signOut()}>Sign Out</button>
)
}
function ChatRoom() {
const messagesRef = firestore.collection('messages');
const query = messagesRef.orderBy('createdAt').limit(50);
const [messages] = useCollectionData(query, { idField: 'id' });
return (
<>
<div className="App ml-20 pl-5">
<h1>HELLO WORLD!</h1>
<main>
{messages && messages.map(msg => <DisplayMessage key={msg.id} message={msg} />)}
</main>
</div>
</>
);
}
function DisplayMessage(props) {
const { text, uid } = props.message;
return (<>
<div>
<p>{text}</p>
</div>
</>)
}
export default App;
And my firebase looks like this after a few minutes online on my local server
Try this and see if it works:
import React, { useRef, useState, useEffect } from "react";
import firebase from "firebase/compat/app";
import "firebase/compat/auth";
import "firebase/compat/firestore";
import { useAuthState } from "react-firebase-hooks/auth";
import { useCollectionData } from "react-firebase-hooks/firestore";
import "./App.css";
import Navbar from "./Navbar";
firebase.initializeApp({
// My configs are here
});
const auth = firebase.auth();
const firestore = firebase.firestore();
function App() {
const [user] = useAuthState(auth);
return (
<>
<div className="App">
<Navbar />
</div>
<section className="place-content-end">
{user ? <ChatRoom /> : <SignIn />}
<SignOut />
</section>
</>
);
}
function SignIn() {
const signInWithGoogle = () => {
const provider = new firebase.auth.GoogleAuthProvider();
auth.signInWithPopup(provider);
};
return (
<>
<button className="sign-in ml-20 pl-5" onClick={signInWithGoogle}>
Sign in with Google to join!{" "}
</button>
<p className="ml-20 pl-5">Welcome to the chat!</p>
</>
);
}
function SignOut() {
return (
auth.currentUser && (
<button className="sign-out ml-20 pl-5" onClick={() => auth.signOut()}>
Sign Out
</button>
)
);
}
function ChatRoom() {
const [messages, setMessages] = useState([]);
useEffect(() => {
const messagesRef = firestore.collection("messages");
const query = messagesRef.orderBy("createdAt").limit(50);
const [data] = useCollectionData(query, { idField: "id" });
setMessages(data);
}, []);
return (
<>
<div className="App ml-20 pl-5">
<h1>HELLO WORLD!</h1>
<main>
{messages.length > 0 &&
messages.map((msg) => (
<DisplayMessage key={msg.id} message={msg} />
))}
</main>
</div>
</>
);
}
function DisplayMessage(props) {
const { text, uid } = props.message;
return (
<>
<div>
<p>{text}</p>
</div>
</>
);
}
export default App;
I added useEffect in line 1. And changed your ChatRoom component.
Quick explanation
useEffect is part of the lifecycle of a Function Component. You give it a function to execute whenever the component mounts or props or state of the component changes. You decide this by what you add as the second argument of the useEffect call. If you give it an [] (empty array), it will only execute when the component is mounted. If you give, for example, [messages] (which a state created by useState) then the function will execute on component mount AND whenever messages change. React keeps track of this for you, this is why React is called react, if data changes it reacts to it and renders accordingly.
The above explanation is the basics of it. But there is also one more cool thing it can do:
If you return a function from inside of useEffect, this function will execute when the component is UNmounted. Like so:
useState(() => {
console.log("Component mounted");
return () => {
console.log("Component unmounted");
};
},[]);
In Class Components we have similar functions, they are called: componentDidMount, componentWillUnmount and others.You can read about it here React State & Lifecyle

Navbar not updating after state change

As the title says my navbar is not changing the fragments after updating the state. I have no idea how to refresh it and other ideas seems to not work for me. I have tried to change the statements.
All i want to do is, after a user logs in successfully the state changes to true and the navbar updates with the corrent components. Thank you !
Home.js
import React, { useEffect } from 'react'
function Home() {
useEffect(()=>{
if(!localStorage.getItem("loggedIn")){
localStorage.setItem("loggedIn",false);
}
},[]);
return (
<div>
Home
</div>
)
}
export default Home
Login.js
import React from 'react';
import './Login.css';
import Axios from 'axios';
import { useEffect, useState } from "react";
import {useHistory} from 'react-router-dom';
function Login() {
const[username,setUsername] = useState('');
const[password,setPassword] = useState('');
const[errorMessage,setErrorMessage] = useState('');
let history = useHistory();
const login = () =>{
console.log(username);
Axios.post("http://localhost:3001/user/login",{username: username,password: password}).then((response) => {
//console.log(response);
if(response.data.loggedIn){
localStorage.setItem("loggedIn",true);
localStorage.setItem("username",response.data.username);
history.push('/');
}else{
setErrorMessage(response.data.message);
}
});
};
return (
<div className="Login">
<h1>Login to your BugTrack account !</h1>
<div className="LoginForm">
<input type="text" placeholder="USERNAME"
onChange={(event)=>{setUsername(event.target.value)}}/>
<input type="password" placeholder="PASSWORD"
onChange={(event)=>{setPassword(event.target.value)}}/>
<button onClick={login}>Login to you account</button>
<h1 style={{color: "red"}}>{errorMessage}</h1>
</div>
</div>
);
}
export default Login
Navbar.js
import React, { useEffect, useState, Component, Fragment } from 'react';
import './Navbar.css';
function Navbar() {
const [loggedIn, setLoggedIn] = useState(false);
useEffect(()=> {
setLoggedIn(localStorage.getItem("loggedIn"));
},[localStorage.getItem("loggedIn")]);
return (
<div className="Navbar">
Home
{!loggedIn ? (
<Fragment>
Profile
</Fragment>
):(
<Fragment>
Register
Login
</Fragment>
)}
</div>
);
}
export default Navbar;
You want to to use localStorage as a useEffect dependency which isn't supports for React to rerender/update the component. Check this: useEffect do not listen for localStorage - it's like duplicate of your question.

Unable to pass prop back to parent component

I'm doing a simple test where I have a name state in the parent component which I update when a button in the child is clicked. But this does not work, and I'm confused on if I'm doing something wrong.
Parent:
import React from "react";
import "./styles.css";
import Hello from "./Hello";
export default function App() {
const [name, setName] = React.useState();
const handle = item => {
setName(item);
};
console.log(name);
return (
<div className="App">
<h1>Hello CodeSandbox</h1>
<h2>Start editing to see some magic happen!</h2>
<Hello test={handle} />
{name}
</div>
);
}
Child:
import React from "react";
export default function App() {
return (
<div>
<button onclick={() => this.props.test("TEST")}>Activate Lasers</button>
</div>
);
}
What am I doing wrong?
Pass the function as a prop.
import React from "react";
export default function App({ handle }) {
return (
<div>
<button onClick={() => handle('TEST')}>Activate Lasers</button>
</div>
);
}
and render the component like
<Hello handle={handle} />
// Get a hook function
const {useState} = React;
function Hello({ handle }) {
return (
<div>
<button onClick={() => handle('TEST')}>Activate Lasers</button>
</div>
);
}
function App() {
const [name, setName] = React.useState();
const handle = item => {
setName(item);
};
return (
<div className="App">
<h1>Hello CodeSandbox</h1>
<h2>Start editing to see some magic happen!</h2>
<Hello handle={handle} />
{name}
</div>
);
}
// Render it
ReactDOM.render(
<App />,
document.getElementById("react")
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
<div id="react"></div>
import React from "react";
export default function App(props) {
return (
<div>
<button onClick={() => props.test("TEST")}>Activate Lasers </button>
</div>
);
}
It should be onClick Secondly you are using this which is pointing to stateless component that is undefined and have no property props within it.
First:
React events are written in camelCase syntax:
onClick instead of onclick.
second
the keyword this in react usually used in-class component, and using it in a functional component to bind it with where you are using it, so now you need to pass the props to the child so that you can access the function.
this should work
import React from "react";
export default function Hello(props) {
return (
<div>
<button onClick={() => props.test("TEST")}>Activate Lasers</button>
</div>
);
}
and third try to use the same naming for thing :) to be more readable
I hope I helped you

How do I change the innerHTML of an element using React?

I want to change innerHTML of a div, when I click on the button. I don't know why, but instead of getting an error, or getting the expected result it deletes to content and replacing it with "[object Object]".
How can I get it work?
import React from 'react';
import Login from './components/login.js';
import SignIn from './components/signin';
import './App.css';
function App() {
function LoginOnClick(){
document.getElementById("wrapper").innerHTML = <SignIn />;
}
return (
<div className="container" id="wrapper">
<button onClick={LoginOnClick}>Login</button>
<Login />
</div>
);
}
export default App;
You can make use of Hooks (Added n React 16.8).
import React, {useState} from 'react';
import Login from './components/login.js';
import SignIn from './components/signin';
import './App.css';
function App() {
const [signIn, setSignIn] = useState(false);
return (
<div className="container" id="wrapper">
{signIn ? <SignIn /> : <> //This is React Fragments syntax
<button onClick={() => setSignIn(true)}>Login</button>
<Login />
</>
}
</div>
);
}
export default App;
With react you don’t have to set the innerHtml to do this, instead the more typical way is to have internal state in your component and conditionally render your SignIn component based off that. To use state the component either needs to be class or use hooks, classes are more traditional so I changed the component to be a class.
To make a class a react component you need to extend the class with the React.Component, this is because react components have lots of internal behaviours that you need to include with your class for it to be considered a component.
So
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
signIn: false,
};
this.LoginOnClick = () => {
this.setState({ signIn: true });
};
}
render() {
if (this.state.signIn) {
return (
<div className="container">
<SignIn />
</div>
);
}
return (
<div className=“container”>
<button onClick={this.LoginOnClick}>Login</button>
<Login />
</div>
);
}
}
Here is a simple way to do it:
import {useState} from "react";
const App = () => {
const [txt, setTxt] = useState("");
setTxt(<p> 'Lorem ipsum dummy text blabla.' </p>);
return(
<div>
{txt}
</div>
)
}
export default App;

Categories

Resources