ReactJS SetState not rerendering - javascript

I have:
JobScreen
handleSetView(mode, e) {
this.setState({
view: mode
});
console.log(this.state.view)
}
render() {
return (
<div className="jobs-screen">
<div className="col-xs-12 col-sm-10 job-list"><JobList view={this.state.view} /></div>
<div className="col-xs-12 col-sm-2 panel-container">
<div className="right-panel pull-right"><RightPanel handleSetView={this.handleSetView} /></div>
...
)
}
RightPanel
render() {
return (
<div>
<div className="controls">
<span className="title">Views <img src="images\ajax-loader-bar.gif" width="24" id="loader" className={this.state.loading ? "pull-right fadeIn" : "pull-right fadeOut"}/></span>
<button onClick={this.props.handleSetView.bind(this, 'expanded')}><img src="/images/icons/32px/libreoffice.png" /></button>
<button onClick={this.props.handleSetView.bind(this, 'condensed')}><img src="/images/icons/32px/stack.png" /></button>
</div>
...
)}
JobList
render() {
var jobs = [];
this.state.jobs.forEach((job) => {
jobs.push(
<Job key={job.id} job={job} view={this.props.view} loading={this.state.loading} toggleTraderModal={this.props.toggleTraderModal} toggleOFTModal={this.props.toggleOFTModal}/>
);
});
return (
<div>
{jobs}
</div>
);
};
The problem is, is that the changing of the view state does not rerender any of the child elements.
How can I get this to work?

Not sure if it is the core of your problem, but:
handleSetView={this.handleSetView}
is wrong, because how js binds this. Use:
handleSetView={this.handleSetView.bind(this)}
instead.
Also,
this.setState({
view: mode
});
console.log(this.state.view)
seems strange; note that this.state is not modified right after you call setState, it may took some time while React dispatches the scheduled setState operation. Put that console.log into render to see when it is actually called.
Finally, make sure, your components do not implement shouldComponentUpdate lifecycle method (you are probably not doing this explicitly, but if your component extends some class other than React.Component this may happen)

this is in the context of the react Component so either pass the reference of this to you function handleSetView or bind this as mentioned by #Tomas

Related

React pass ref throw functional components in different levels

I would like to scroll to menu element in a page.
I have the menu component which is not a parent of components to which I would like to scroll.
I have found this post that describe a similar problem
Passing ref to a child We want the ref to be attached to a dom element, not to a react component. So when passing it to a child
component we can't name the prop ref.
const myRef = useRef(null)
return <ChildComp refProp={myRef}></ChildComp> } ```
Then attach the ref prop to a dom element. ```jsx const ChildComp =
(props) => {
return <div ref={props.refProp} /> } ```
Here's my app structure
Menu component:
const MenuApp = () => {
return (
<div>
<div className="desktop-menu">
<div className="menu-item a-propos">
<p className='button'>Me découvrir</p>
</div>
<div className="menu-item competences">
<p className='button'>Compétences </p>
</div>
<div className="menu-item experiences">
<p className='button'>Experiences</p>
</div>
<div className="menu-item formation">
<p className='button'>Formation </p>
</div>
</div>
</div>
)
}
The parent is app component
<div className="App">
<div className="hero">
<HeaderApp />
<ApprochApp />
</div>
<Apropos />
<Competences />
<Experiences />
<Formation />
<Recom />
<Contact />
<Footer />
</div >
I would like that mu menus scrolls to the react components in the main App component
So how can I passe the reference from the menu component to the app and use it in components to scroll ?
I do not understand your problem completely though. However, one thing I can see from your question is that you're not forwarding the ref properly.
What you need in this case is forwardRef.
Basically, what you need to do is to create the childComponent as something like this:
const childComponent = React.forwardRef(({...otherProps}, ref) => {
return (<><div ref={ref}>Component content </div></>)
})
Where you need to use the component all you need to do is this:
const parentComponent = () => {
const reveiwsRef = React.useRef("");
return (
<div>
<childComponent ref={reviewsRef} />
</div>
);
}
You can find more info about this on the react documentation: Forwarding-Refs
I have hope this helps though

Pure render and button onClick inline setStates

When talking about pure render methods in React and how setting state inside of render is a serious anti-pattern, how strictly we are speaking about this? I get that if I do a setState inside a render function, which doesn't require any user input, it can create infinite loops and re-renders.
What I don't understand is, does this rule apply also when writing a page element that receives input from user? I mean, what's the difference between these two ways to write a simple click-handler for a button:
render() {
return(
<div className="container-fluid info-modal">
<div className="row">
<div className="col col-12">
<InfoModal active={this.state.modalActive}>
<h2>Fine dining recipes</h2>
<p>Here you can publish your fine dining recipes. Don't forget to
include every ingredient needed!</p>
<Button
title="ok"
onClick={() => {
this.setState({ modalActive: false })
}}
/>
</InfoModal>
</div>
</div>
</div>
)
}
vs.
render() {
return(
<div className="container-fluid info-modal">
<div className="row">
<div className="col col-12">
<InfoModal active={this.state.modalActive}>
<h2>Fine dining recipes</h2>
<p>Here you can publish your fine dining recipes. Don't forget to
include every ingredient needed!</p>
<Button
title="ok"
onClick={() => {
this.closeModal()
}}
/>
</InfoModal>
</div>
</div>
</div>
)
}
I get that for a more complicated components, probably the right way to do this would be to use a click-handler which this class receives as an property, but for simple use cases, are there really some concrete harm in setting the state inside an inline click-handler?
When docs say that you must not setState within render it means that that the setState function must not be called as soon as we render and not that setState cannot be written inside render
so when you write
<Button
title="ok"
onClick={() => {
this.setState({ modalActive: false })
}}
/>
You are not actually calling setState in render but you are calling it on click action of button which are 2 different things
So whether you write
<Button
title="ok"
onClick={() => {
this.closeModal()
}}
/>
or
<Button
title="ok"
onClick={() => {
this.setState({ modalActive: false })
}}
/>
are equivalent if you just setState inside closeModal
A call that will not be accepted is below
<Button
title="ok"
onClick={this.setState({ modalActive: false })}
/>

Cannot Render Nested Maps In ReactJS

I am trying to nest maps to render an array within an object
My Cards Component Render Method (Not Nested, Working):
render() {
return (
<div class="mediator-container">
{this.state.routeList.map(
(route, index) =>
<Card busName={this.state.routeList[index].$.tag} />
)}
<span class="loader">
<span class="loader-inner"></span>
</span>
</div>
);
}
My Cards Component Render Method (Nesteing, Not Working!!):
render() {
return (
<div class="mediator-container">
{this.state.routeList.map((route, index) =>
{
{
this.busTitleToDirectionName(this.state.routeList[index].$.tag).map(busDir => {
<Card busName={busDir} />;
});
}
}
)}
<span class="loader">
<span class="loader-inner"></span>
</span>
</div>
);
}
busTitleToDirectionName(int) returns an array of Strings
My Card Subcomponent's render method:
render() {
// Logging to see if render method is called
console.log("Ran");
return (
<div className="card">
<div className="card-header">
<div className="bus-name">
<p>{this.props.busName}</p>
</div>
</div>
</div>
);
}
How it looks like without nesting when it does work (Not enough reputation to post images so here are the links):
https://i.gyazo.com/66414925d60701a316b9f6325c834c12.png
I also log in the Card subcomponent so that we know that the Card component was ran and it logs that it did get called without nesting
https://i.gyazo.com/fb136e555bb3df7497fe9894273bf4d3.png
When nesting, nothing renders and the Card subcomponent isn't being called as there is no logging of it
https://i.gyazo.com/38df248525863b1cf5077d4064b0a15c.png
https://i.gyazo.com/d6bb4fb413dfc9f683b44c88cce04b8a.png
You can try below code in your nested case. In the nesting of map you have to wrap your nested map within a container. Here I use React.Fragment (<> ) as a container.
return (
<div class="mediator-container">
{this.state.routeList.map((route, index) =>
<>
{
this.busTitleToDirectionName(this.state.routeList[index].$.tag).map(busDir => {
<Card busName={busDir} />;
});
}
</>
)}
<span class="loader">
<span class="loader-inner"></span>
</span>
</div>
);
Hope it will help you!!
Thanks, Prahbat Kumar, but I figured out the issue. I had to return the subcomponent from the nested map here is the code:
render() {
return (
<div class="mediator-container">
{this.state.routeList.map((route, index) =>
this.busTitleToDirectionName(this.state.routeList[index].$.tag).map(busDir => {
return <Card busName={busDir} />
})
)}
<span class="loader">
<span class="loader-inner"></span>
</span>
</div>
);
}

How do I stop the call stack from over loading?

My problem is simple yet infuriating. All I want to do is have an onClick event that when triggered changes the state on the component. The only problem is if I don't stop the addActiveClass function from running initially with the loaded state prop than I get a call stack overload because this component is being rendered by a .map function.
The second I remove the if (this.state.loaded) { //logic } over my state change logic I get
Please help me understand why I can't do this simple thing in React.
class IndividualQA extends Component {
constructor(props) {
super(props);
// this.addActiveClass = this.addActiveClass.bind(this);
this.state = {
active: false,
loaded: false
};
// this.state({ arrowState: this.props.arrowClass });
}
addActiveClass = (load) => {
if (this.state.loaded) {
const currentState = this.state.active;
console.log(this.state);
this.setState({ active: !currentState });
}
};
render() {
return (
<div>
<div className="row">
<div className="col-xl-11 col-lg-11 col-md-11 col-sm-10 col-10">
{this.props.data.Q}
</div>
<div className="col-xl-1 col-lg-1 col-md-1 col-sm-2 col-2 Question">
<a
data-toggle="collapse"
href={`#QA${this.props.id}`}
id="arrowSVG"
onClick={this.addActiveClass()}
>
<img
style={{ height: "30px" }}
className={this.state.active ? "transform" : ""}
src={downArrow}
/>
</a>
</div>
</div>
<div className="row collapse" id={`QA${this.props.id}`}>
<div className="col-xl-11 col-lg-11 col-md-11 col-sm-11 col-11 As-a-long-time-Kiva">
{this.props.data.A}
</div>
</div>
<hr />
</div>
);
}
}
export default IndividualQA;
Your problem is in here
<a
data-toggle="collapse"
href={`#QA${this.props.id}`}
id="arrowSVG"
onClick={this.addActiveClass()} //here
>
This way addActiveClass will be called on every render and can cause a infinty loop.
You need to change it to
<a
data-toggle="collapse"
href={`#QA${this.props.id}`}
id="arrowSVG"
onClick={this.addActiveClass} // without '()'
>
The handler on the a tag should be this.addActiveClass not this.addActiveClass()

React JS :Cannot read property 'dataTransfer' of undefined in children component

i want make a drag-drop app
but a has 1 error here
Cannot read property 'dataTransfer' of undefined in children component
class DragDrop extends Component {
render() {
return (
<div className="Item">
<div className='Start'>
<div id="draggable"
draggable="true"
onDragStart={this.event.dataTransfer.setData('text/plain',null)}>
{this.props.item}</div>
</div>
<div className='div2'></div>
<div className='div2'></div>
</div>
);
}
}
help me !!!
You need to pass a function to onDragStart to access event
onDragStart={(event) => event.dataTransfer.setData('text/plain',null)}
Of course, a better way to handle this is to create a separate function, for readability.
class DragDrop extends Component {
dragFunction(event) {
event.dataTransfer.setData('text/plain', null)
}
render() {
return (
<div className="Item">
<div className='Start'>
<div id="draggable"
draggable="true"
onDragStart={this.dragFunction}>
{this.props.item}</div>
</div>
<div className='div2'></div>
<div className='div2'></div>
</div>
);
}
}

Categories

Resources