I have 2 components, Component A and Component B which are rendered in the same page. What I need is to scroll to a div of the Component B once I click on a button in the Component A.
Component B:
import React, { FC, useRef } from 'react';
const Footer: FC<Props> = ({ children }) => {
const commentSection = useRef(null);
const gotoCommentSection = () => window.scrollTo({top: commentSection.current.offsetTop, behavior: "smooth"})
return (
<>
<div className="footerClass" ref={commentSection}>
<div className="container">{children}</div>
</div>
</>
);
};
export default Footer;
if I insert this button in Component B, the scrolling function is working. But how can I achieve that from the Component A?
<button type="button" onClick={gotoCommentSection}>Scroll to Area</button>
I think it will work to move useRef up the component tree to Component A along with your scroll function. Then use React.forwardRef to apply that ref to the element in Component B. Looks like this is a decent example: https://stackoverflow.com/a/49832065/9325243
Related
I'm trying to understand the rendering in ReactJS. I'm following this tutorial from YouTube, but I want a better grasp on the subject. The video explains that if you pass down the child component
<Child/>
Then it will trigger a render of the parent and the child.
However if you pass down
{props.children}
Then it will only update the parent, if there are no changes to the children. But what if I have a series of different children? What if I have 20 children or 100? And I want to pass a prop to a specific child? Say I want to pass down a prop to the 50th child (or any other). Then how would I go about in doing this?
Say that I want to pass down these constants, would the children only re-render if they receive a prop or would they all re-render?
const [childA, setChildA] = useState("In Child A")
const [childB, setChildB] = useState("In Child B")
I tried using the code from How to pass props to {this.props.children}
{React.Children.map(props.children, function(child){
if(React.isValidElement(child)){
let clone = React.cloneElement(child, {...props})
return clone
}
But I'm not sure what I'm doing, I'm think I'm in the right path, but I'm not sure how to get what I'm looking for.
Parent component
import React, { useState } from 'react';
function ParentCount(props) {
const [count, setCount] = useState(0)
console.log("Parent render")
return (
<div>
<button onClick={()=>setCount(v=>v+1)}>Parent Increase +1</button>
Parent count is {count}
Children count
{React.Children.map(props.children, function(child){
if(React.isValidElement(child)){
let clone = React.cloneElement(child, {...props})
return clone
}
})}
</div>
);
}
export default ParentCount;
App component
function App() {
return (
<div className="App">
<ParentCount>
<ChildCount></ChildCount>
<ChildCount></ChildCount>
</ParentCount>
</div>
);
}
export default App;
Child component
import React, {useState} from 'react';
function ChildCount(props) {
const [count, setCount] = useState(0)
console.log("Child render")
return (
<div>
<button onClick={()=>setCount(v=>v+1)}>Child Increase +1</button>
<div>Child count is {count}</div>
</div>
);
}
export default ChildCount;
the meaning of the first lines you wrote is this:
if you pass a prop to a child component, react will only update that component for you. ex:
<ChildComponent prop1 = 'hi'>
if you add a whole new child component to your Component, react will update your parent too:
function ParentComponent () {
const [update, setUpdate] = useState(0);
let updateComponent = null;
if (update === 1) {
updateComponent = <UpdateComponent></UpdateComponent>;
}
return (
<div>
{ updateComponent }
</div>
)
}
sorry for bad example
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.
I am developing a component where i have to change state on scrollview scroll, means on onScroll function call. I have some child components in it as well ... when I do setState parent component re-renders and also re-renders to its child components.
There is a child component having banner and description which I donot update on this screen but it also re-renders and create flickering effect which looks weird.
const [state, setState] = useState('');
setState('MOVING');
I also convert that child component from functional component to PureComponent but it still re-rendering.
There is no state update for this child component but it re-render as its parent re-render.
Please help to stop re-rendering of this child component as there is not state change in it.
Any solution to make it fix.
thanks.
Your question is related to this issue. How to stop re render child component when any state changed in react js?
To stop re-render on child components you can use React memo, or useMemo if you use react hooks.
I have same issue about rerendering on child when I used React.context with lot of unneeded data passing to child. So, u can limit what should child component refer to rerender when props change with useMemo
import React, { Component, useState, useMemo } from "react";
import { render } from "react-dom";
import Child from "./components/child.js";
import "./style.css";
function App() {
const [number, setNumber] = useState(0);
function handleOnClick() {
setNumber(number + 1);
}
//memo child not rendering when state update, only render child props update.
const memoChild = useMemo(() => <Child />, []);
// useMemo's second arguments is state variable name. example [number]. if 'number' gets update, child component rerender will be happen.
// const memoChild = useMemo(() => <Child />, [number]);
return (
<div>
<h1>Use Memo</h1>
<div className="box">
<h2>Parent Component</h2>
<h4>Number : {number}</h4>
<button onClick={() => handleOnClick()}> Increment </button>
</div>
<div className="box">
<h2>Normal child component </h2>
<Child /> {/*Every state update it gets rerendered */}
</div>
<div className="box">
<h2>Memo child Component </h2>
{memoChild}
</div>
</div>
);
}
render(<App />, document.getElementById("root"));
for more references
Re-rendering component tree is something react manages well. In terms of performance, if you are looking for a way to manage not necessary re-renders I suggest you have a look at a few useful hooks, useMemo, useCallback, and a higher order component React.memo.
With these three hooks, you are able to prevent child components from re-rendering, if parent is updated.
const Parent = () => {
const [childAState, setChildAState] = useState();
useEffect(() => {
setChildAState('Child A Updated');
}, []);
return (
<>
<ChildA childAState={childAState}/>
<ChildB />
</>
);
};
const ChildA = () => React.memo((props) => {
return <h1>Child A</h1>
});
const ChildB = () => React.memo((props) => {
return <h1>Child B</h1>
});
In the above example, ChildB wont re-render if a state in Parent does change and leads to an update in ChildA.
Further reading: React.memo
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
I am still very new to React and I am trying to recreate a navigation bar that was originaly made with HTML, CSS and JS.
I have a Layout component and a Navbar component. In the Navbar component I have a button that when clicked should apply an inline style or a CSS class to the <main>{children}</main> element in the Layout component.
The Navbar element is used inside the Layout element, so I am wondering if this is even possible?
layout.js
import React from "react"
import { useStaticQuery, graphql} from "gatsby"
import Navbar from "./navbar"
const Layout = ({ location, title, children }) => {
const data = useStaticQuery(graphql`
{
site {
siteMetadata {
menuLinks {
link
name
}
}
}
}
`)
return (
<div>
<Navbar pages={ data.site.siteMetadata.menuLinks } />
<main>{children}</main>
</div>
)
}
export default Layout
navbar.js
import React, { useState } from "react"
import { Link } from "gatsby"
import styles from "./styling/navbar.module.less"
const Navbar = ( props ) => {
const [navbarState, setNavbarState] = useState(false);
let toggleNavbar = () => {
console.log("Navbar toggle - Activated")
setNavbarState((navbarState) => !navbarState)
}
window.addEventListener('resize', windowResized)
return (
<nav id={"navigation-bar"}>
<div className={`${styles.navLinks} ${navbarState? styles.navActive:""}`}>
{props.pages.map((page, index) => (
<Link key={page.name} className={`${styles.navLink} ${styles.navLinkHoverEffect} ${navbarState? styles.navAnimate:""}`}
style={{animationDelay: `${index / 7 + 0.5}s`}} to={page.link}>
{page.name}
</Link>
))}
</div>
<div className={`${styles.burger} ${navbarState? styles.toggle:""}`} onClick={toggleNavbar}>
<div className={styles.line1}></div>
<div className={styles.line2}></div>
<div className={styles.line3}></div>
</div>
</nav>
)
}
export default Navbar
Sure it's possible. When you want the child, Navbar, to change something in the parent (normally state) you can pass a function down. In Layout:
const [classes, setClasses] = useState('');
const setClassNames = (classnames) => {
setClasses(classnames)
}
Pass this function down to the child as a prop.
<Navbar pages={ data.site.siteMetadata.menuLinks } setClassNames={setClassNames} />
When the action occurs on the child, say an onClick event then call that function with the classes string you want to set on main.
Then in your parent component, Layout change the line to:
<main className={classes}>{children}</main>
Of note, the way it's currently setup you could just pass the setClasses to Navbar but I used a new function to just to show a more common scenario when you have to customize anything. Also you should use useCallback on the function setClassNames in Layout if you don't want Navbar to re-render every time.
Feel free to leave a comment with questions.