I'm grabbing some data from a redux action to pull into my React component. In the render() method, I am using an if/else check to see if that data was pulled in. IF the data is null and the "loading" boolean is still true, I want to display a spinner. ELSE - show the data.
When I hit the webpage, the component will show the spinner for half a second, as it's still null, then once the data is pulled in, it will show that.
my question is, in traditional JS, if the "if" statement is reached and the profile is still null will it not just stay on the spinner? Since that if/else expression on page load showed null should it not just stay on my spinner if that was the condition that was met on page load? How does it go back to that statement after the first run and hit the else block afterwards?
render() {
const {profile, loading} = this.props.profile;
let profileContent;
if(profile === null || loading){
profileContent = <Spinner/>;
} else {
profileContent = (
<div>
<div className="row">
<div className="col-md-6">
<Link to="/profiles">Back To Profiles</Link>
</div>
<div className="col-md-6"></div>
</div>
<ProfileHeader/>
<ProfileAbout/>
<ProfileCreds/>
<ProfileGithub/>
</div>
);
}
A React Component works by calling the render() function whenever the component state changes by default.
There are ways to modify this behavior by adding component lifecycle methods to your component.
Here is the official React documentation:
https://reactjs.org/docs/react-component.html
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.
Currently, I am in
http://localhost:3000/?servicekey=kuazqvyj&lang=en
When I click on a button in react I put
history.push("/questions", { ...data });
but it changes the URL into
http://localhost:3000/questions
which I don't want. I want to route but don't want to change the url.
Yes you can do them by using the State object and adding in ternary operators to your JS snippets in your react app, and you can change like that, but it is not a preferred approach, but here you go
import {useState, React} from 'react';
let [info, setInfo] = useState(true);
if(info){
return(
<div>
This says info is true
</div>
)
} else {
return(
<div>
This says info is false
</div>
)
So you can set the state using a button or so and you can do the rest, I have also used this idea in my project and as it was for a small section it did fine :)
Let's say I've got a Tooltip component that shows & hides depending on whether there is text data for it or not:
{this.state.tooltipText && (
<Tooltip
text={this.state.tooltipText} />
)}
If I wanted to transition this component in and out, I might instead include a boolean on prop and let the component manage transitioning out itself.
<Tooltip
on={this.state.tooltipText !== null}
text={this.state.tooltipText} />
With this setup, though, I lose the text prop right when the transition out should begin. There is very clearly never a state where on is false and I still have access to the text prop.
Is there a good way to handle this scenario?
Should the component keep an internal record of the previous state of tooltipText?
Or is it best to use two properties to track the state of the tooltip (tooltipOn and tooltipText) and never erase this.state.tooltipText?
Should the component keep an internal record of the previous state of tooltipText?
Yes. Otherwise the parent would have to decide when the transition starts / ends, which is not his authority.
Actually componentWillReceiveProps is best for this as you can access the current & next props:
componentWillReceiveProps(nextProps) {
if(this.props.text && !nextProps.text) {
this.fadeOut();
} else if(!this.props.text && nextProps.text) {
this.setState({ text: nextProps.text });
this.fadeIn();
}
}
Then the parent just has:
<Tooltip text={this.state.tooltipText} />
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 have a component that shows a modal to pop up some content in my map. I have a pretty straight forward set up :
The JSX looks like this :
<Modal show={this.props.results.showPreviewModal} >
{myPreviewContent}
</Modal>
2 action-creators to open, close, and set the current item :
export function previewAsset(result) {
return {
currentResult: result,
type: actions.PREVIEW_ASSET
};
}
export function closePreviewModal() {
return {
type: actions.CLOSE_PREVIEW_MODAL
};
}
And their reducers :
case actions.PREVIEW_ASSET:
return state.set('currentPreview', action.currentResult).set('showPreviewModal', true);
case actions.CLOSE_PREVIEW_MODAL:
return state.set('showPreviewModal', false);
Now, this seems to work fine. However, the issue is that the component that has the modal inside of it is inside a map, as it is a singular search result (each result component has a some functionality so it is it's own component that is mapped over with results). The issue is that if I have 10 results, this modal opens 10 times when I click the button that fires the previewAsset action.
This makes sense, because the showPreviewModal is accessible by all components, but what I am wondering is if there is a way to make then unique for each component individually, so only the 1 modal opens, not all 10. Unsure how to approach this within react/redux, would very much appreciate any advice, thanks!
An approach I've used successfully is to pull the Modal component out of the loop (or map() in this case), and have a reducer for currentItem or something similar, which gets set when an item is selected (you could also use currentItemIndex, and then select the current item based on that in your connect() call).
In the parent component, you'd have the Modal as a child, and only display it if that currentItem is not null.
Here's a quick JSBin example to show you what I mean:
http://jsbin.com/fefoxoy/edit?html,js,console,output