Detect focus on children component with react - javascript

I have a parent component and in general I render input fields inside it.
is there a way to know if the children input has focus?
<Component>
<input />
</Component>
const Component = (props) => return (<div className="nice">{props.children}</div>)

I've created a sandbox that you can check here : https://codesandbox.io/s/chris-lisangola-c53ri-c53ri
From the link that you've posted i seems like the main problem is the way to handle event triggered from a child component to the parent through props.If i'm wrong please let me know.
I've created a child component like this :
import React from "react";
export default function Input(props) {
const { checkFocus } = props;
return <input onFocus={checkFocus} />;
}
And in the child component i've added a event listener of type focus that is passed to the parent through the checkFocus.
In the parent component App:
import React, { useState } from "react";
import FormInput from "./FormInput";
import "./styles.css";
export default function App() {
const [text, setText] = useState("");
const checkFocus = (e) => {
console.log(e.type);
if (e.type === "focus") {
setText("Focus");
}
};
return (
<div className="App">
<h1>Handle Focus : {text}</h1>
<FormInput checkFocus={checkFocus} />
</div>
);
}
I've done a very basic test so that of there is a focus in the child's input , the text Focus is displayed in the h1 tag

Related

Problem when pass data in ReactJS with props and state

I have the problem when I try to pass the props through the function component .In parent component I have a state of currentRow with return an array with object inside, and I pass it to child component. It return a new object with an array inside it. What can I do to avoid it and receive exact my currentRow array.
there is example of the way I do it
Parent component
import React, { useState } from "react";
import ToolBar from "./Toolbar";
function Manage() {
const [currentRow, setCurrentRow] = useState();
console.log("from manage", currentRow);
return (
<div>
<ToolBar currentRow={currentRow} />
</div>
);
}
export default Manage;
Child Componet
import React from 'react'
function ToolBar(currentRow) {
console.log("from toolbar", currentRow);
return(
<div></div>
);
}
export default ToolBar
And this is my Log
enter image description here
Try accessing it like below:
import React from 'react'
function ToolBar({currentRow}) {
console.log("from toolbar", currentRow);
return(
<div></div>
);
}
export default ToolBar
A React component's props is always an object. The reason for this is that otherwise it would be impossible to access the properties of a component which received multiple props.
example:
<SomeComponent prop1={prop1} prop2={prop2} />
---
const SomeComponent = (props) => {
console.log(props.prop1);
console.log(props.prop2);
}
So in order to resolve your issue, you could destructure the props object in your ToolBar component like this:
const ToolBar = ({ currentRows }) => {
...
}
Just keep in mind that a component will always receive its props as an object. There is no way to change that as of right now.

set value on a click button from a function component to another const component React

All I want here is when I press the search button in Hero.jsx , I set a value to the guest constant in Hotelcards.jsx , any solutions ?
the guest value that I wanna set is on this file.
Hotelcards.jsx
import { Link } from "react-router-dom";
import React,{useState,useEffect} from 'react';
import styles from '../styles/HotelListCards/HotelCards.module.css';
import {Checkkin as checkkin} from "./Hero";
import {Checkkout as checkkout} from "./Hero";
import {rowss as rows } from "./Hero";
import {notavailableat as notavailableat } from "./Hero";
import {prices as prices } from "./Hero";
const HotelCards = ({ idroom , title, status = true, price, img }) => {
const [guests, setGuest] = useState('')
const [qty, setTitle] = useState('')
var total_price = 0;
if(prices.length!==0){
for (var i=0;i<prices.length-1;i++){
total_price+=parseFloat(prices[i]);
}
}
};
And the button that will trigger the event of changing the value is on this file.
Hero.jsx
import React, {useEffect, useState, useCallback} from 'react';
import styled from 'styled-components';
import homeImage from '../assets/booking-bg.jpg';
import styles from '../styles/HotelListCards/HotelCards.module.css';
import {differenceInDays, format} from "date-fns";
var Checkkin = 0;
var Checkkout= 1;
let notavailableat="";
let rowss=[];
let prices =[];
export {Checkkin,Checkkout,rowss,notavailableat,prices};
export default function Hero() {
const [availdata, setavailData] = useState([]);
const [isLoading, setIsLoading] = useState(false);
}
<div className="search">
<button >Search</button>
</div>
We will need a bit more of your code to really understand how this is being implemented, however it appears to me you want your search button, the Hero component class, to pass up its values to the parent HotelCard. If that is the case, you can pass function handlers from HotelCard to Hero, hero can then call the function onClick, and set the data from the Hero inside the HotelCard using the callback function passed as a prop to the Hero Component. Hope this helps, the general idea above will work but you may need to change which component is which as its not a complete code base/implementation as you have posted.
So the solution was wrapping both siblings in a parent component and handle the state inside the parent component. Then you easily can share the state between any siblings that you want and use the state inside the child components. :
in the parent component :
function App() {
const [selectedMode, setSelectedMode] = useState('open')
.
.
.
<>
<NewNavbar />
<Hero setSelectedMode={setSelectedMode} />
<Services />
<Options selectedMode={selectedMode}/>
<ScrollToTop />
<Footer />
{/* <PaymentSummaryFinal1 />*/}
</>
in the first sibling Hero:
export default function Hero({setSelectedMode}) {
const onButtonClick=(mode)=>{
setSelectedMode(mode)
}
.
.
.
<button onClick={()=>onButtonClick('closed')} >Search</button>
and on the other sibling Options.jsx
export default function Options({selectedMode}) {
.
.
.
return (
<div className={`${styles.containers}`}>
<div>
<HotelCards
mode={selectedMode} // pass it to the child of this sibling
/>
</div>
)}
</div>
);
}
Thanks to Chad S in the comments.

How to display JSX returned from other function inside return?

I'm trying to build a weather application using openweathermap api. As you can see below in the code, I use a boolean state to check when the form is summitted so I can pass that value to the <Result> component(which I checked with hard code and it works). I want the function changeCity(in the App) to return the <Result> component with the value of city passed and in the same time to change the cityEmpty state. But there I got the problem when I pass that in the return() {(cityEmpty) ? changeCity() : null}
import React, {useState} from 'react';
import Result from "./components/Result";
import Search from "./components/Search";
import './App.css';
function App() {
const [city, setCity] = useState ("");
const [cityEmpty, setCityEmpty] = useState(false);
const changeCity = () => {
setCityEmpty(false);
return (<Result city={city}/>);
}
return (
<div className="App">
<Search city={city} setCity={setCity} cityEmpty={cityEmpty} setCityEmpty={setCityEmpty}
/>
{(cityEmpty) ? changeCity() : null}
</div>
);
}
export default App;
import React from "react"
function Search({city, setCity, cityEmpty, setCityEmpty}){
const handleInputChange = (e) => {
setCity(e.target.value);
}
const handleSumbit = (e) => {
e.preventDefault();
console.log(cityEmpty);
setCityEmpty(true);
console.log(cityEmpty);
setCity("");
}
return(
<div>
<form onSubmit={handleSumbit}>
<input
type="text"
placeholder="Insert city"
value={city}
onChange = {handleInputChange}
>
</input>
</form>
</div>
);
}
export default Search
You can't call a state update inside the render of a component. Remember that whenever state is updated, it will re render the component. This will cause an infinite loop in your component.
Component renders
changeCity is called
Inside changeCity, setCityEmpty is called
Go back to step 1 for rendering.
Instead, consider checking if city is empty in your handleInputChange and calling setCityEmpty inside that function.
EDIT: To clarify a function that returns a component is completely fine, this is all components are really. Functions (or in previous react versions: classes) returning other components.
you don't have to return JSX from function. In your case it is pretty straightforward to use.
import React, {useState} from 'react';
import Result from "./components/Result";
import Search from "./components/Search";
import './App.css';
function App() {
const [city, setCity] = useState ("");
const [cityEmpty, setCityEmpty] = useState(false);
return (
<div className="App">
<Search city={city} setCity={setCity} cityEmpty={cityEmpty} setCityEmpty={setCityEmpty}
/>
{cityEmpty && <Result city={city}/>}
</div>
);
}
export default App;
import React from "react"
function Search({city, setCity, cityEmpty, setCityEmpty}){
const handleInputChange = (e) => {
setCity(e.target.value);
}
const handleSumbit = (e) => {
e.preventDefault();
console.log(cityEmpty);
setCityEmpty(true);
console.log(cityEmpty);
setCity("");
}
return(
<div>
<form onSubmit={handleSumbit}>
<input
type="text"
placeholder="Insert city"
value={city}
onChange = {handleInputChange}
>
</input>
</form>
</div>
);
}
export default Search
Not sure what the problem you're seeing is but I noticed you're setting state inside of a render function, which is a bad pattern. Any state changes will trigger a re-rendering of the component and if you set state within a render function then you'd have an infinite loop of re-renderings (but.
Try removing setCityEmpty(false) in changeCity.
const changeCity = () => {
return (<Result city={city}/>);
}
So how would you update cityEmpty? It's not clear what the end goal is here. With more info, we can find a better implementation.

How do i click a button in parent component and access the data in child component?

I am working with the concepts of ReactJS and stumbled upon this very interesting case,
I have a button in my parent component, which when clicked will access a simple string defined in child component.
I understand to pass data from parent to child we use, and to a child to parent we have to use callback functions, But I am not sure how do I use callback function in this scenario. I have played around a little with defining function etc but nothing seems to really work.
My Main.js file
import React from "react";
import Child from "./Child";
function handleClick(props) {
console.log("clicked");
}
function Main(props) {
return (
<div>
<button onClick={handleClick}>click</button>
{console.log(props)}
</div>
);
}
export default Main;
My Child.js component
import React from "react";
function statement() {
return "A sentence";
}
function Child(props) {
// let sentence = "This is from the child component";
return (
<div>
<p>The child says {props.name} </p>
</div>
);
}
export default Child;
Thank you for reading, sorry if it sounds too basic. Any help would be much appreciated.
you can create a ref in parent component and pass it to child component and then access the child state through that ref like:
function Main(props) {
const child = useRef()
const handleClick = () => {
// get child state
child.current.getState()
}
return <Child innerRef={child} />
}
function Child({ innerRef }) {
const [someState, setSomeState] = useState()
useImperativeRef(innerRef, () => ({ getState: () => someState }), [someState])
return <SomeComponent />
}
You can read more about above code in official docs.

Live updates between React components based on state

My (simplified) goal:
Show a form input's text content beside the form itself and update the reflected text as the input text changes. The form lives within a React component, and the displayed text lives inside another one.
I can use the component state to control the input's text and change the state based on onChange form event. But how can I also change the state of the displayed text so that I get the live updates I'm looking for?
Input and output components have the same parent component.
Here's my input component:
import React, { useState } from "react";
function InputBoxTest() {
const [inText, setInText] = useState("");
const handleChange = event => {
setInText(event.target.value);
// My instinct is to setOutText here, but I can't...
};
return (
<textarea className="form-control" id="comment" onChange={handleChange}>
{inText}
</textarea>
);
}
export default InputBoxTest;
My output component:
import React, { useState } from "react";
function OutputBoxTest() {
const [outText, setOutText] = useState("");
return <p>{outText}</p>;
}
export default OutputBoxTest;
And my parent component:
import React from "react";
import InputBoxTest from "./InputBoxTest";
import OutputBoxTest from "./OutputBoxTest";
function Test1(props) {
return (
<>
<div className="row">
<div className="container-fluid col-sm-7">
<InputBoxTest />
</div>
<div className="col-sm-5">
<OutputBoxTest />
</div>
</div>
</>
);
}
export default Test1;
You could move the State Hook from InputBoxText into the ParentComponent Test1
InputBoxText is then used for displaying and updating the state
OutputBoxText is used for displaying only
import React from "react";
import InputBoxTest from "./InputBoxTest";
import OutputBoxTest from "./OutputBoxTest";
function Test1(props) {
const [inText, setInText] = useState("");
const handleChange = event => {
setInText(event.target.value);
};
return (
<>
<div className="row">
<div className="container-fluid col-sm-7">
<InputBoxTest text={inText} handleChange={handleChange} />
</div>
<div className="col-sm-5">
<OutputBoxTest text={inText}/>
</div>
</div>
</>
);
}
export default Test1;
function InputBoxTest(props) {
return (
<textarea className="form-control" id="comment" onChange={props.handleChange}>
{props.text}
</textarea>
);
}
export default InputBoxTest;
function OutputBoxTest(props) {
return <p>{props.text}</p>;
}
export default OutputBoxTest;
If you need to share some state between 2 components, you need to move that state in their (at least first) parent. You can read more about it here.
Basically what this means is that your Test1 component should be holder of your textarea value.
Please see this example based on your code.

Categories

Resources