Is it possible to render HTML in a function with React? - html

I'm new to React, and I'm trying to render html with a function in React.
This is my code:
import React, { Component, useRef, useState, useEffect } from 'react';
import { render } from 'react-dom';
import Searc from './search'
const HandleSearch = () => {
const [name, searchName] = useState("")
const [comments, getComments] = useState([])
const nameForm = useRef(null)
const onSubmitSearch = async(e) => {
e.preventDefault();
try {
// do something
} catch (error) {
console.log(error.message);
}
}
const displayComment = async() => {
try {
const form = nameForm.current
console.log(form['name'].value)
const name = form['name'].value
const response = await fetch(`http://localhost:5000/folder/${name.toLowerCase()}`)
const jsonData = await response.json()
getComments(jsonData)
} catch (error) {
console.log(error.message)
}
}
useEffect(() => {
displayComment()
}, [])
return(
<div className="container">
<div className="form-group">
<h1 className="text-center mt-5">SEARCH MY LANDLORD</h1>
<form ref={nameForm} className="mt-5" onSubmit={onSubmitSearch}>
<Search name={'name'}/>
<div className="d-flex justify-content-center">
<button type="submit" className="d-flex btn btn-primary" onClick={displayComment}>Search</button>
</div>
</form>
<div>
<div>
{/*<tr>
<td>Mary</td>
</tr>*/}
{comments.map(comment => (
<tr>
<td>{comment.problem}</td>
</tr>
))}
</div>
</div>
</div>
</div>
)
}
export default HandleSearch;
The issue I have is that the full list of comments appears before I trigger the displayComments function (once it's trigger it works).
<div>
{/*<tr>
<td>Mary</td>
</tr>*/}
{comments.map(comment => (
<tr>
<td>{comment.problem}</td>
</tr>
))}
</div>
Is it possible to render the above html in the displayComments function so nothing appears before I actually specified which data to display?

You need to remove the useEffect if you want the state to only be set on the button click, because as of right now the state is being set with the useEffect() which is loading when your component is first rendered.

Related

Failed to create check box preview using defaultChecked in reactjs

I'am new using reactjs and looks like I am following the tutorial with old version of react. So, I have some roles with their permissions, the problem is when I want to make changes of the role permissions I need to preview them with previous checked permission. As you can see the image below I have the permissions data, but when I try to put them into checkbox using default checked there is nothing happen.
here is my code
RoleEdit.tsx
import axios from "axios";
import { SyntheticEvent, useEffect, useState } from "react";
import { Navigate, useParams } from "react-router-dom";
import Wrapper from "../../components/Wrapper";
import { Permission } from "../../models/permissions";
const RoleEdit = (props:any) => {
const [permissions, setPermissions] = useState([]);
const [selected, setSelected] = useState([] as number[]);
const [name, setName] = useState('');
const [redirect, setRedirect] = useState(false);
const {id} = useParams();
useEffect( () => {
(
async () => {
const response = await axios.get('permissions');
setPermissions(response.data);
const {data} = await axios.get(`roles/${id}`);
setName(data.name);
setSelected(data.permissions.map((p : Permission) => p.id));
}
)();
}, [id]);
const check = (id: number) => {
if(selected.some(s => s === id)){
setSelected(selected.filter(s => s !== id));
return;
}
setSelected([...selected, id]);
}
const submit = async (e: SyntheticEvent) => {
e.preventDefault();
await axios.post('roles', {
name,
permissions: selected
});
setRedirect(true);
}
if(redirect){
return <Navigate to="/roles"/>
}
return(
<Wrapper>
<form onSubmit={submit}>
<div className="mb-3 mt-3 row">
<label className="col-sm-2 col-form-label">Role Name</label>
<div className="col-sm-10">
<input className="form-control" defaultValue={name} onChange={e => setName(e.target.value)}/>
</div>
</div>
<div className="mb-3 row">
<label className="col-sm-2 col-form-label">Permissions</label>
<div className="col-sm-10">
{permissions.map((p: Permission) => {
return(
<div className="form-check form-check-inline col-3" key={p.id}>
<input className="form-check-input" type={"checkbox"}
value={p.id}
defaultChecked={selected.some( s => s === p.id)}
onChange={()=> check(p.id)}/>
<label className="form-check-label">{p.name}</label>
</div>
)
})}
</div>
</div>
<button className="w-100 btn btn-lg btn-primary" type="submit">Save</button>
</form>
</Wrapper>
);
};
export default RoleEdit;
please help me solve the problem so I can continue the tutorial. Thankyou

How to pass variable between components in react?

I have two components, Navbar and ShoppingList. When the user is logged in so I get response from api, I set isLoggedIn variable to true. What I want to do is to show "Logout" button on my navbar when the user is logged in and hide it where he is not. How to pass this value to Navbar component?
ShoppingList fragment
import React, { useState, useEffect } from 'react'
import axiosInstance from '../apis/apiURLS';
function ShoppingList() {
export const [isLoggedIn, setIsLoggedIn] = useState(false);
const getShoppingList = async () => {
await axiosInstance.get('/shoppinglist/')
.then(response => {
if(response){
setIsLoggedIn(true)
setShoppingList(response.data)
}
})
.catch(e => {
console.log(e);
});
}
useEffect(() => {
getShoppingList();
}, [])
Navbar fragment
<div className='navbar'>
<div className='menu-bar-logout' onClick={handleLogout}>
<div class="icon">
</div>
<span>Logout</span>
</div>
</div>

How do I share the value of a variable to another component in react?

How can I pass variables around to different components? I have a hook in the VariableWithData component which then multiplies the state when a button is clicked. How do I transfer the data of the variable multiplied onto the component NeedVariableData so that I can display the value on the <h1> tag?
//src/app.js
export const app = () => {
return (
<div>
<VariableWithData />
<NeedVariableData />
</div>
)
}
// src/components/VariableWithData.js
import { useState } from "react"
export const VariableWithData = () => {
const [state, setState] = useState(2)
function multiplyData(){
const multiplied = state * 2;
}
return (
<div>
<input type="submit" onClick={multiplyData}/>
</div>
)
}
// src/components/NeedVariableData.js
export const NeedVariableData = () => {
return (
<div>
<h1>{multiplyData}</h1>
</div>
)
}
You need to lift the state up.
import { useState } from "react"
export const App = () => {
const [count, setCount] = useState(2);
const handleClick = {
setCount(c => c * 2);
}
return (
<div>
<VariableWithData onClick={handleClick} />
<NeedVariableData multiplyData={count} />
</div>
)
}
// src/components/VariableWithData.js
export const VariableWithData = ({ onClick }) => {
return (
<div>
<button onClick={onClick}/>
</div>
)
}
// src/components/NeedVariableData.js
export const NeedVariableData = ({ multiplyData }) => {
return (
<div>
<h1>{multiplyData}</h1>
</div>
)
}

TypeError: links.map is not a function React

I'm working with reactjs typescript and cannot seem to prevent this error when trying to display JSON data from the server:
import React, { useRef, useState } from "react";
import useHttp from "../hooks/usehttp";
const HomePage: React.FC = () => {
const [links, setLinks] = useState([]);
const ref = useRef<HTMLInputElement>(null);
const { request } = useHttp();
const pressHandler = async (event: React.KeyboardEvent) => {
if (event.key === "Enter") {
try {
const data = await request(
"http://localhost:5000/api/link/generate-guest",
"POST",
{ from: ref.current!.value },
{}
);
alert(data.message);
console.log(data.link.to); // the link => localhost:5000/jshdadsa
setLinks(data.link.to);
console.log(links); // shows undefined ?????
} catch (error) {
alert(error);
}
}
};
return (
<>
<div className="row">
<div className="col s8 offset-s2" style={{ paddingTop: "2rem" }}>
<div className="input-field">
<input
placeholder="Enter link"
id="link"
type="text"
ref={ref}
onKeyPress={pressHandler}
/>
<label htmlFor="link">Enter link</label>
</div>
<div>
{ {links.map((link: any) => {
return (
<ul className="collection with-header">
<li className="collection-item">{link}</li>
</ul>
);
})} }
</div>
</div>
</div>
</>
);
};
export default HomePage;
Not sure what i am missing.
Use this code in order to update the array of link in your example:
setLinks([...links, data.link.to])

How to manually trigger click event in ReactJS?

How can I manually trigger a click event in ReactJS?
When a user clicks on element1, I want to automatically trigger a click on the input tag.
<div className="div-margins logoContainer">
<div id="element1" className="content" onClick={this.uploadLogoIcon}>
<div className="logoBlank" />
</div>
<input accept="image/*" type="file" className="hide"/>
</div>
You could use the ref prop to acquire a reference to the underlying HTMLInputElement object through a callback, store the reference as a class property, then use that reference to later trigger a click from your event handlers using the HTMLElement.click method.
In your render method:
<input ref={input => this.inputElement = input} ... />
In your event handler:
this.inputElement.click();
Full example:
class MyComponent extends React.Component {
render() {
return (
<div onClick={this.handleClick}>
<input ref={input => this.inputElement = input} />
</div>
);
}
handleClick = (e) => {
this.inputElement.click();
}
}
Note the ES6 arrow function that provides the correct lexical scope for this in the callback. Also note, that the object you acquire this way is an object akin to what you would acquire using document.getElementById, i.e. the actual DOM-node.
Here is the Hooks solution:
import React, {useRef} from 'react';
const MyComponent = () => {
const myRefname= useRef(null);
const handleClick = () => {
myRefname.current.focus();
}
return (
<div onClick={handleClick}>
<input ref={myRefname}/>
</div>
);
}
Got the following to work May 2018 with ES6
React Docs as a reference: https://reactjs.org/docs/refs-and-the-dom.html
import React, { Component } from "react";
class AddImage extends Component {
constructor(props) {
super(props);
this.fileUpload = React.createRef();
this.showFileUpload = this.showFileUpload.bind(this);
}
showFileUpload() {
this.fileUpload.current.click();
}
render() {
return (
<div className="AddImage">
<input
type="file"
id="my_file"
style={{ display: "none" }}
ref={this.fileUpload}
/>
<input
type="image"
src="http://www.graphicssimplified.com/wp-content/uploads/2015/04/upload-cloud.png"
width="30px"
onClick={this.showFileUpload}
/>
</div>
);
}
}
export default AddImage;
You can use ref callback which will return the node. Call click() on that node to do a programmatic click.
Getting the div node
clickDiv(el) {
el.click()
}
Setting a ref to the div node
<div
id="element1"
className="content"
ref={this.clickDiv}
onClick={this.uploadLogoIcon}
>
Check the fiddle
https://jsfiddle.net/pranesh_ravi/5skk51ap/1/
Hope it helps!
In a functional component this principle also works, it's just a slightly different syntax and way of thinking.
const UploadsWindow = () => {
// will hold a reference for our real input file
let inputFile = '';
// function to trigger our input file click
const uploadClick = e => {
e.preventDefault();
inputFile.click();
return false;
};
return (
<>
<input
type="file"
name="fileUpload"
ref={input => {
// assigns a reference so we can trigger it later
inputFile = input;
}}
multiple
/>
<a href="#" className="btn" onClick={uploadClick}>
Add or Drag Attachments Here
</a>
</>
)
}
Riffing on Aaron Hakala's answer with useRef inspired by this answer https://stackoverflow.com/a/54316368/3893510
const myRef = useRef(null);
const clickElement = (ref) => {
ref.current.dispatchEvent(
new MouseEvent('click', {
view: window,
bubbles: true,
cancelable: true,
buttons: 1,
}),
);
};
And your JSX:
<button onClick={() => clickElement(myRef)}>Click<button/>
<input ref={myRef}>
Using React Hooks and the useRef hook.
import React, { useRef } from 'react';
const MyComponent = () => {
const myInput = useRef(null);
const clickElement = () => {
// To simulate a user focusing an input you should use the
// built in .focus() method.
myInput.current?.focus();
// To simulate a click on a button you can use the .click()
// method.
// myInput.current?.click();
}
return (
<div>
<button onClick={clickElement}>
Trigger click inside input
</button>
<input ref={myInput} />
</div>
);
}
this.buttonRef.current.click();
Try this and let me know if it does not work on your end:
<input type="checkbox" name='agree' ref={input => this.inputElement = input}/>
<div onClick={() => this.inputElement.click()}>Click</div>
Clicking on the div should simulate a click on the input element
let timer;
let isDoubleClick = false;
const handleClick = () => {
if(!isDoubleClick) {
isDoubleClick = true;
timer = setTimeout(() => {
isDoubleClick = false;
props.onClick();
}, 200);
} else {
clearTimeout(timer);
props.onDoubleClick();
}
}
return <div onClick={handleClick}></div>
for typescript you could use this code to avoid getting type error
import React, { useRef } from 'react';
const MyComponent = () => {
const fileRef = useRef<HTMLInputElement>(null);
const handleClick = () => {
fileRef.current?.focus();
}
return (
<div>
<button onClick={handleClick}>
Trigger click inside input
</button>
<input ref={fileRef} />
</div>
);
}
If it doesn't work in the latest version of reactjs, try using innerRef
class MyComponent extends React.Component {
render() {
return (
<div onClick={this.handleClick}>
<input innerRef={input => this.inputElement = input} />
</div>
);
}
handleClick = (e) => {
this.inputElement.click();
}
}
imagePicker(){
this.refs.fileUploader.click();
this.setState({
imagePicker: true
})
}
<div onClick={this.imagePicker.bind(this)} >
<input type='file' style={{display: 'none'}} ref="fileUploader" onChange={this.imageOnChange} />
</div>
This work for me
How about just plain old js ?
example:
autoClick = () => {
if (something === something) {
var link = document.getElementById('dashboard-link');
link.click();
}
};
......
var clickIt = this.autoClick();
return (
<div>
<Link id="dashboard-link" to={'/dashboard'}>Dashboard</Link>
</div>
);