If I have multiple divs whose are rendered from data array using array.map() method like that:
import React,{ ReactDOM } from 'react'
import { useState,useEffect,useRef } from 'react'
import getResults from '../api/getResults'
...
function Results (props){
const [results,setResults]=useState([])
useEffect(()=>{
setResults(getResults(props.season))},
[props.season])
return (
{results.map((elem,index)=>{
return (
<div key={index} onClick={()=/*what should I do to render inside this div?*/>}>{elem}</div>
)
})}
<Details/> //I want to render this jsx inside the clicked div
)
........
}
How to get reference of specific clicked div to render Details jsx component inside this div? I tried use useRef hook but it always return the last div.
Track the clicked element in state. For example, consider this state value:
const [clickedElement, setClickedElement] = useState();
By default the value is undefined. You can update the value to some identifier when clicking one of the elements:
<div key={index} onClick={() => setClickedElement(index)}>{elem}</div>
Now each click updates state indicating which element was clicked.
Then you can use that state value to determine what to render. For example:
<div key={index} onClick={() => setClickedElement(index)}>
{elem}
{clickedElement === index ? <Details/> : null}
</div>
Basically any way you approach it, the structure is pretty much always the same:
Track information in state.
Events (e.g. a click event) update state.
UI is rendered based on state.
Related
I'm currently learning React, and trying to get a sense of how components re-render. I have this parent component which renders three items. Each item just renders an <li>
function App() {
console.log("Parent Rerendered");
return (
<div>
<ul>
<Item1 />
<Item2 />
<Item3 />
</ul>
</div>
);
}
Item2 is a bit different because it also renders an "x" that will un-render the component when it's clicked:
function Item2() {
const [visible, setVisible] = useState(true);
const makeInvisible = () => {
setVisible(false);
};
console.log("Item 2 Rerendered");
return visible ? (
<div>
<li>
Second Item <span onClick={makeInvisible}>X</span>
</li>
</div>
) : null;
}
When I test this in my browser and click the "x", I can see from the console that Item2 gets re-rendered. However, none of the other components get re-rendered including the parent component. However the parent component does change, so how does this happen without re-rendering it.
If that's a bit confusing, here's an illustration of the initial state, my expectations, and reality. What am I misunderstanding about how React re-renders components?
A component rerenders when it sets state, or when its parent rerenders1. App has no state and no parent, so it will never rerender. It doesn't need to though. React saves the virtual DOM from the previous render, so it still knows that App is supposed to be a div surrounding a ul surrounding an Item1, Item2, and Item3. If the Item2 rerenders, and returns a null instead of a div, react will update the part of the real DOM that the Item2 is responsible for, by removing the div. The rest of the page remains intact
1) or if a context it consumes changes, or in a class component when you call forceUpdate. But for most cases, it's just state and parent that matter.
Instead of clicking onto <Item2 /> go to the Dev-tools -> Explorer -> select the Element and press delete. The view will also change, the gap will close, without react being involved at all.
React is responsible to update the DOM, the layout is done by the browser. So when <Item2 /> decides it wants to be rendered as null instead of a div>li (??? invalid markup ) and therefore removes the respective DOM-nodes, the browser will update the layout.
And the parent component has nothing to do with all that.
I have a section that is made out of 2 components:
trigger component
show/hide component
Basically when I click on trigger component, new component under will appear. This is handled simple by useState
const [toShow, setToShow] = useState(0);
And then I am using onClick method:
onClick={() => setToShow(1)}
Showing the element under trigger component:
{toShow === 1 && (
<div className="show-box" id="myHiddenComponent">
<HiddenComponent />
</div>
)}
Problem is, I need to access the hidden component with id="myHiddenComponent" from my Navbar. That means, the component will be not set to show. But link should understand that it has to set it to be opened and then scroll to the component. Is something like that possible with React ?
Right now I am using Hashlink
<HashLink smooth to='#myHiddenComponent'>
GO TO HIDDEN SECTON
</HashLink>
But that does not work unfortunately, since the section is hidden.
you need to set state of toShow to 1 onClick on HashLink component
I am new with formik and I have a very annoying problem that I am stuck on with days. So basically I have a parent component in which I have a code like this:
const refs=[]
{data.map((v,i) =>
<Child formikRef={refs}}/> )}
And my child component uses formik:
...
<Formik
innerRef={i => props.formikRef.push(i)}
....../>
So my Child component is rendered a couple of times in my parent component, and I need to track the values of each in my parent component. To be more clear, when I click on button that is located in my parent component, I need to have the values from each (I need to pass data from child to parent component). That's why I am using innerRef. The problem is that I am using an array of refs to track values of each rendered , and a new value is added in the array every time I change a field in my form, so I have far more elements in my array than I should have. I think innderRef is triggered each time a change in a field is made, instead of only onSubmit. How I can solve this problem? Pls help.
You could try like below, Here we are passing index value to Child component to have Formik ref in the same place.
const refs=[]
{data.map((v,i) =>
<Child index={i} formikRef={refs}}/>
)}
<Formik
innerRef={props.formikRef[props.index]}
/>
I'm using a component library and I cannot figure this out. I'm new to react and javascript and need help.
There is a component in the library that renders a header panel with tabs.
Component
|_Component.Tab
The Tab component has 2 states that change its appearance when it is clicked. But the click handler and state changes have to be defined by me outside of Tab component. How do I do this?
Seems to me by your question that you need to use props to pass the function to change state from the Component to the Tabs. Something like this:
Component
changeState(value) {
this.setState({ appearance: value });
}
render() {
return (
<div>
<Tab
appearance={this.state.appearance}
onChangeState={this.changeState}
/>
</div>
);
}
Tab
render() {
console.log('Appearance: ', this.props.appearance); // Use it for whatever you need it
return (
<div>
<Button
onClick={(value) => this.props.onChangeState(value)} />
</div>
);
}
Not sure why do you want to handle a function and it’s state outside of the component when it has to be within the Tab component. But here is the solution what you actually have to do in your Tab component to handle your state
Bind your handler function inside a constructor like below
Eg:
this.handlerFunction = this.handlerFunction.bind(this)
Call this.handlerFunction reference in your tab onClick
Eg:
onClick={this.handlerFunction}
Set state in handlerFunction
Eg:
handlerFunction(event){
this.setState({
tabClicked: event.target.value
})
}
Else I guess The outside component should be a child component that you are talking about. If so pass your tab click state as props to your outside component (i.e., child component) and receive that state as props in your child component and do setState there.
If you are still unclear then
Post your component code here. With Just theory it’s little difficult to understand the actual problem that you are talking about.
I'm trying to use an html element with the type="range" to make a range slider that will update a state value as I slide it back and forth. It works smoothly if I simply console.log e.target.value inside of onInputChange() without setting the state, but if I try to setState with the e.target.value, it lags so much that it's unusable. I've also tried setting the value={this.state.rangeValue} inside , with no success. Here is an example of the relevant code:
export default class App extends Component {
constructor() {
super();
this.onInputChange = this.onInputChange.bind(this);
this.state = {
rangeValue: 50
}
}
onInputChange(e) {
this.setState({ rangeValue: e.target.value});
}
render() {
var {rangeValue} = this.state;
// this logs unbearably slow and I want to be able to pass this value
// to a child component as a prop as it updates
console.log(rangeValue)
return (
<div className="map-controls">
<input type="range" onChange={this.onInputChange}></input>
<ExampleComponent rangeValue={this.state.rangeValue} />
</div>
);
}
}
I wonder if my package could help you out?
https://github.com/bluebill1049/react-smooth-range-input
import react from 'react';
import Slider from 'react-smooth-range-input';
export default () => <Slider value={1} min={1} max={30} onChange={/** you can put your callback here */} />;
#user3737841 It seems that you are updating the state of the component on onInputChange() handler. On each step value change of the input range slider, the setState is called and re-render happens. This is to be very costly to re-render on each input change.
If you avoid updating the state, you'll probably save some renders and your performance will improve.
You can also use defaultValue instead of value. Then the <input> is considered as uncontrolled and any user interactions are immediately reflected by element itself without invoking render function of your component.
Just replace value={this.state.rangeValue} with defaultValue={this.state.rangeValue}. Pass the slider value as prop to the <ExampleComponent /> component regrdless of component state.