how to know the component rendering condition in react js - reactjs

I have one component which is rendering as child as well or user can navigate to that component directly from menu of UI. I am facing one issue now is, if that component as child then its working fine but when I click upon menu to navigate directly then my getDerivedStateFromProps() function is throwing an error as
TypeError: Cannot read property 'length' of undefined
Below is my code. It will work fine if I send a data from parent component to this component and render it from parent component.
static getDerivedStateFromProps(props, state) {
if (props.data.length)// this line is throwing an error when I directly come to this component from menu {
const data = props.data;
return { custData : data };
}
return null;
}
How can I check the condition that not to execute above logic if I am coming to this component directly.

You can double-check like this :
if (props.data && props.data.length)

Check to see if the data exists
if (props?.data)

Related

React can not access variable from return

I am very new to React and I can not solve this issue for a very long time. The idea is the following, I get some user info from database and pass it into cookies. From react side I get this cookies as JSON object and I need to render menu for user depending on values in this object. Right now I pass this object that I get from cookies from parent Component and I try to access it from Settings component. The issue is that I can see access this object from test function, however when I try to access this data from return it gives me undefined error. The function that returns value from cookies is sync, I have no idea why that might happen, please help.....
Since this.state.shopSettings["new_orders"] is boolean, use ternary.
Don't copy props to the state inside constructor as the constructor is executed only once. So updates to the props won't be reflected in the component.
Like this
<button onClick={this.test}>
{props.shopSettings && (props.shopSettings["new_orders"] ? 'true button' : 'false button')}
</button>
It solves very easily with this code, now I can access any key from shopSettings inside return without any issues
class Index extends React.Component {
state = {
shopSettings: Cookies.getJSON('shopSettings')
}
render() {
const {shopSettings} = this.state
if (!shopSettings) {
return null
}
return (
<div>Hello</div>
)
}

declaring jsx element as a global variable

Hello is there a way to declare react component globally so that when I render the same component the values are persisted, I am aware the redux or some other state management lib can be used, but for the time being I want to use this option cuz I'm in the middle of the project. For example
constructor() {
this.accountInfoJSX = <AccountInformation ref={(sender) => {
this.accountInformationMod = sender;
}} />;
}
I can try to save the element in the global variable but each time when the render is called it initializes a new instance.
Edit:
yes sure. i have this method. I have 2 buttons on screen based on which i render different components. User can made some changes on each component, so i am trying to to use same component so that the changes made in component are persisted. i have tried returning this.accountInfoJSX as well as this.accountInformationMod not its not working. On former it re render the new component and values are lost and on latter it show nothing on screen.
get getCurrentScreen() {
if (this.state.selectedScreen == Screens.accountInformation) {
return this.accountInformationMod;
} else if (this.state.selectedScreen == Screens.myInformation) {
return <MyInformation />;
}
}

React conditional rendering not updating state in child component

I'm having a weird problem with conditional rendering in which state isn' going down into a child component. I have a viewer template, with a PDF viewer component and a Web viewer component (using an iframe). Depending on what comes back from the server as a media_type value, the appropriate component gets rendered. That's all working fine.
Externally, I have a sibling component responsible for searching inside the content, and in order to do so, it has to pass the search query up to the parent component, which then updates the parent state and then gets passed to the child as a prop. The reason for this is different content requires different search implementation, which is implemented inside the viewer component.
Apparently, my method of conditional rendering is breaking the search query prop update in the child component. None of the component update methods are being called when the prop changes, and therefore the search execution never gets called.
The sibling component calls this method in the common parent:
/**
* Search query execution handler. Passes the state as a prop to the catalog for search
* execution
* #param e Keyword or query string from SearchPanel
*/
searchQueryHandler(e) {
this.setState({
searchRequest: e
});
}
Parent component render method
render() {
let viewer = <div />;
if (this.state.link.media_type === 1)
viewer = <PDF file={this.state.link.id}
setOverlayVisibility={this.props.setOverlayVisibility}
searchQuery = {this.state.searchRequest}
searchMatchHandler={this.searchMatchHandler}
searchResultSelection={this.state.searchResultSelection}
/>;
else if (this.state.link.media_type !== '')
viewer = <WebViewer link={this.state.link}
setOverlayVisibility={this.props.setOverlayVisibility}
searchQuery={this.state.searchRequest}
/>;
return (
<Content>
<ContentLeft>
{viewer}
</ContentLeft>
<ContentRight>
<SidePanel institution={this.state.institution}
link={this.state.link}
searchQueryHandler={this.searchQueryHandler}
searchResults={this.state.searchResults}
searchResultClickHandler={this.searchResultClickHandler}
/>
</ContentRight>
</Content>
)
}
Now, the searchQueryHandler method is being hit by the event fired off in SidePanel, but none of componentWillReceiveProps, shouldComponentUpdate, willComponentUpdate are called inside PDF or WebViewer. I suspect this has to do with the if/else block inside render, but not sure how else to implement this.
The answer to this was the parent component was blocked from updating by a shouldComponentUpdate implementation that did not take into account the new state of the search query. As such, it was returning false all the time, and thus blocking propagation of state update to the appropriate child component.
shouldComponentUpdate(nextProps, nextState) {
return this.state.link !== nextProps.link || this.state.searchRequest !== nextState.searchRequest;
}
was the fix.
So simple, and yet so frustrating.

React Router "Link to" does not load new data when called from inside the same component

Background
I am building an app with the following details
react
react-router
redux
it is universal javascript
node js
Problem
When routing with the Link tag from component to component it works perfectly. It calls the data that the component requires and renders the page. But when I click on a Link that uses the same component as the current one all I see is the url change.
Attempts
Things I have tried to get this to work.
Attempt 1
So far I have tried the steps in this question but the solution wont work for me. This was the code I implemented
componentWillReceiveProps(nextProps) {
if (nextProps.article.get('id') !== this.props.article.get('id')) {
console.log('i got trigggerd YESSSSSSSSSSSSSSS');
}
}
But the variable nextProps is always the same as the current props.
Attempt 2
I decided to call the same code I use in componentWillMount but that didn't work either.
componentWillMount() {
let { category, slug } = this.props.params;
this.props.loadArticleState({ category, slug });
}
It just creates an infinite loop when I put this into componentWillReceiveProps.
Conclusion
I belief the problem is clicking the link never calls the data associated with it. Since the data is loaded with
static fetchData({ store, params }) {
let { category, slug } = params;
return store.dispatch(loadArticleState({ category, slug }));
}
Any help is appreciated.
Solution I Used
I created a function to test if the previous data is the same as the changed data.
compareParams(prevProps, props) {
if (!prevProps || typeof prevProps.params !== typeof props.params) {
return false;
}
return Object.is(props.params, prevProps.params);
}
So this tests
are there any previous props?
and then if the props are equal to the previous props?
then return false if there are if this is the case
if not then we see compare props and previous props parameters
In ComponentDidUpdate
In the compoonentDidUpdate we use this function to determine if the data should be updated
componentDidUpdate(prevProps) {
if (this.compareParams(prevProps, this.props)) {
return;
}
this.props[this.constructor.reducerName](this.props.params);
}
Conclusion
This code updates the body of a page that uses the same react component if it receives new data.
maybe you can try use onChange event on Route component, check Route API and then signal to child component that refresh is needed...

react triggers onclick when component is mounted

I am passing a component to a nested component a onClick method that modifies the state of the parent component.
Somehow the method is being called when a component (not sure if it's parent or child) is being mounted. And now, I'm getting the following error message:
Uncaught Error: Invariant Violation: setState(...): Cannot update
during an existing state transition (such as within render). Render
methods should be a pure function of props and state.invariant
The code for passing the child looks like the following
var playlists = this.props.data.map(function(playlist) {
return (
<PlaylistItem key={playlist.id}
data={playlist}
showPlaylistCode={this.getPlaylistCodeData}
/>
);
}.bind(this));
In your Playlist Item component, line 20, try changing it to:
<div className="playlistCode i mfi-qr-code" onClick={this.props.showPlaylistCode.bind(this, this.props.data.id)}></div>
When you need to send an argument to a function that's used onClick in React, you need to use bind. As with any use of bind(), the first argument should be the context of this, and the second should be what you want to send to the click handler function.

Resources