I want to create a button that changes its text based on the state of the application. I want the old text to fade out, and then the new text to fade in.
Here's a pen where I've implemented what I want in pure JS.
How would I achieve the same effect in React - or what would be the best approach?
For reference, here is my JSX:
<div className="buttons">
<div className="half">
<button className="button" onClick={this.chooseLeft}>{this.state.leftButton}</button>
</div>
<div className="half">
<button className="button" onClick={this.chooseRight}>{this.state.rightButton}</button>
</div>
</div>
Edit:
I tried with ReactCSSTransitionGroup, but it didn't work quite as expected. It added the new text, then faded out the old one while fading in the new one.
Use ReactCSSTransitionGroup, part of react's animation add-ons. It's designed for your exact use case.
Had a similar use case and ended up using a timer to update a couple state variables.
One state var to track the message text, another to track application of a fade class in the components className. The fade class basically controls opacity of the text block.
For instance:
...
// in some handler code
this.setState({fading: true}); // fade out
this.timer = setTimeout(_ => {
this.setState({msg: 'Some new text'}); // swap the text
this.setState({fading: false}); // fade back in
}, 500); // animation timing offset
// in render
render() {
const {msg, fading} = this.state;
return (
<h1 className={`${fading ? 'faded' : ''}`}>
{msg}
</h1>
);
}
Related
I am using Lit 2.3 and try to use the the #vaadin/vaadin-dialog component from within my own Lit component to show an input field and access the value of it when a user clicks the Okay button. My own render method looks something like this:
render() {
return html`
<vaadin-dialog
header-title="settings"
.opened="${this.dialogOpened}"
#opened-changed="${this.dialog_opened_change}"
${dialogRenderer(this.renderDialog, [])}
${dialogFooterRenderer(this.renderFooter, [])}
></vaadin-dialog>
`
}
And the renderDialog method that renders the inside of the dialog looks like this:
private renderDialog = () => html`
<div>
<div class="settings-dialog">
<label for="userid">User-Id</label><input name="userid" id="userid" type="text" value=${this.userid}>
</div>
</div>
`
I can successfully open and close the dialog. What I don't understand is how to get the value of the input field after the dialog closed. And in fact I would also like to initialize the value of the input field without using a local state (${this.dockid}), but that at least works.
I tried accessing the values from within "this.dialog_opened_change" but I don't seem to understand what to hang my querySelector on to get to my <input>.
This is what I do, currently, but it looks unorthodox at best to me:
I call the method _apply_settings from a button within the dialog's footer
private renderFooter = () => html`
<button class="modal-ok" id="apply_settings" #click="${this._apply_settings}">
</button>
`
And in the _apply_settings I poke around in the DOM to get to the vaadin-dialog's overlay and use that as a starting point for querySelector:
private _apply_settings(e: Event) {
let overlay = (<HTMLElement>e.target)?.parentNode?.parentNode
let settings = new Settings()
settings.user_id = (<HTMLInputElement>overlay?.querySelector("#userid")).value
this._close_settings()
}
While this works for now, I have trouble believing that it is the way it should be. The documentation unfortunately stops at showing a dialog and never explains how to access things so I wonder if I am missing something entirely trivial?
I face a problem with react.js, I'm new to it and haven't seen such questions as mine so far.
My problem is that I wanted to reproduce epic games website to learn react, but I can't manage to do the dropdown layout menu.
So here is what I've done so far (tried many things but my final result is this) :
const [selectedMenu, setSelectedMenu] = useState(null);
And the html part :
<div className="col-2" onMouseEnter={() => setSelectedMenu(1)}>
<div className="wrapper">
<li className="select-none bot_line">news & events</li>
</div>
{selectedMenu === 1 && (
<div
className="bot_menu"
onMouseEnter={() => setSelectedMenu(1)}
onMouseLeave={() => setSelectedMenu(null)}
>}
But this is not what I want exactly, I have 7 element to set from hidden to visible.
The way I want to do it is by targeting each child components with the "onMouseEnter" function through the col-2 element.
What I wish is to change the previous class to a new one by hovering col-2 to show the bot_menu onMonseEnter.The css part is done, my trouble is only with the react part.
So the previous className to be "hidden" and onMouseEnter set it to "visible" className.
And to do it by targeting child elements so I only have to do it once and not 7 times.
Please
I'm trying to add style to an element in my return of a react component, but I want to achieve this without adding a class. My text editor auto fills a style option, but I believe the syntax is wrong, since when trying to add a function on an onClick event, its a little different when its in the return of a react element. For example, instead of
onClick=function()
its
onClick={() => {function()}}
I'm hoping that instead of style={"background-color: green;"} its a different syntax to actually allow style changes once it hits the dom.
In-line styles can be done, and here is a code example as you have not provided one.
for example, lets inline style an h1 tag
<h1 style={{background-color:'green', color:'white'}}>This is a tilte</h1>
more can be found here
additionally, I would not recommend inline styling as it's not industry-standard and can cause your code to become bloted.
Style tags in react can indeed contain a references to functions.
I am not fully sure if you are working with React component classes or component functions, but your syntax can besides as follows. Create a variable called customStyle which will contain a function that returns your required style object:
customStyle = () => { return { color: 'red' } };
You can then reference customStyle inside markup as follows:
<div style={this.customStyle()}>My Element</div>
idont know if i understood your question well, You can achieve what you want by making a style state, then mutate it whatever style you want with setState
const [style, setStyle] = useState({})
const App = () => {
return <div style={style}>
<button onClick={() => setStyle({color: 'red'})}>handler button </button>
</div>
}
I'm taking the simple Facebook flux-chat example and plugging in nicer scroll bars for the "MessagesSection" component
The plugin in for the scrollbars is here
I installed the module, required it in the "MessagesSection" and wrapped the new component around the list of messages like so:
render: function() {
var postListItems = this.state.posts.map(getPostListItem);
return (
<div className="post-section">
<h3 className="post-thread-heading">{this.state.thread.name}</h3>
<ul className="post-list" ref="postList">
<ScrollbarWrapper>
<div>
{postListItems}
</div>
</ScrollbarWrapper>
</ul>
<PostComposer threadID={this.state.thread.id}/>
</div>
);
}
**Note: I also tried wrapping it around the unordered list as well.
Yet the scroll bars remain unchanged(still the basic chrome ones that were there before).
What am I doing wrong that the scroll bars are not changing?
Copy paste this CSS in the index.html: https://github.com/ojame/react-scrollbars/blob/master/examples/views/home/examples/custom-scrollbar.css
And use the class on the wrapper like so: <ScrollbarWrapper className="ScrollbarContent--custom">
I've been hiding/showing react components by not rendering them, for example:
render: function() {
var partial;
if (this.state.currentPage === 'home') {
partial = <Home />;
} else if (this.state.currentPage === 'bio') {
partial = <Bio />;
} else {
partial = <h1>Not found</h1>
}
return (
<div>
<div>I am a menu that stays here</div>
Home Bio
{partial}
</div>
);
}
but just say that the <Bio/> component has lots of internal state. Everytime I recreate the component, it loses it's internal state, and resets to it's original state.
I know of course that I could store the data for it somewhere, and pass it in via props or just globally access it, but this data doesn't really need to live outside of the component. I could also hide/show components using CSS (display:none), but I'd prefer to hide/show them as above.
What's the best practice here?
EDIT: Maybe a better way to state the problem is to use an example:
Ignore React, and assume you were just using a desktop app that had a configuration dialog with a Tab component called A, which has 2 tabs, named 1 and 2.
Say that tab A.1 has an email text field and you fill in your email address. Then you click on Tab A.2 for a second, then click back to Tab A.1. What's happened? Your email address wouldn't be there anymore, it would've been reset to nothing because the internal state wasn't stored anywhere.
Internalizing the state works as suggested in one of the answers below, but only for the component and it's immediate children. If you had components arbitrarily nested in other components, say Tabs in Tabs in Tabs, the only way for them to keep their internal state around is to either externalize it somewhere, or use the display:none approach which actually keeps all the child components around at all times.
It just seems to me that this type of data isn't data you want dirtying up your app state... or even want to even have to think about. It seems like data you should be able to control at a parent component level, and choose to either keep or discard, without using the display:none approach and without concerning yourself with details on how it's stored.
One option would be to move the conditional inside the component itself:
Bio = React.createClass({
render: function() {
if(this.props.show) {
return <p>bio comp</p>
} else {
return null;
}
}
});
<Bio show={isBioPage} />
Whether this is "best practise" or not probably depends on the exact situation.
Unfortunately, style={{display: 'none'}} trick only works on normal DOM element, not React component. I have to wrap component inside a div. So I don't have to cascade the state to subcomponent.
<div className="content">
<div className={this.state.curTab == 'securities' ? 'active' : ''}>
<Securities />
</div>
<div className={this.state.curTab == 'plugins' ? 'active' : ''}>
<Plugins />
</div>
</div>
Looks like official documentation suggests hiding stateful children with style={{display: 'none'}}
The fundamental problem here is that in React you're only allowed to mount component to its parent, which is not always the desired behavior. But how to address this issue?
I propose the solution, addressed to fix this issue. More detailed problem definition, src and examples can be found here: https://github.com/fckt/react-layer-stack#rationale
Rationale
react/react-dom comes comes with 2 basic assumptions/ideas:
every UI is hierarchical naturally. This why we have the idea of components which wrap each other
react-dom mounts (physically) child component to its parent DOM node by default
The problem is that sometimes the second property isn't what you want
in your case. Sometimes you want to mount your component into
different physical DOM node and hold logical connection between
parent and child at the same time.
Canonical example is Tooltip-like component: at some point of
development process you could find that you need to add some
description for your UI element: it'll render in fixed layer and
should know its coordinates (which are that UI element coord or
mouse coords) and at the same time it needs information whether it
needs to be shown right now or not, its content and some context from
parent components. This example shows that sometimes logical hierarchy
isn't match with the physical DOM hierarchy.
Take a look at https://github.com/fckt/react-layer-stack/blob/master/README.md#real-world-usage-example to see the concrete example which is answer to your question (take a look at the "use" property):
import { Layer, LayerContext } from 'react-layer-stack'
// ... for each `object` in array of `objects`
const modalId = 'DeleteObjectConfirmation' + objects[rowIndex].id
return (
<Cell {...props}>
// the layer definition. The content will show up in the LayerStackMountPoint when `show(modalId)` be fired in LayerContext
<Layer use={[objects[rowIndex], rowIndex]} id={modalId}> {({
hideMe, // alias for `hide(modalId)`
index } // useful to know to set zIndex, for example
, e) => // access to the arguments (click event data in this example)
<Modal onClick={ hideMe } zIndex={(index + 1) * 1000}>
<ConfirmationDialog
title={ 'Delete' }
message={ "You're about to delete to " + '"' + objects[rowIndex].name + '"' }
confirmButton={ <Button type="primary">DELETE</Button> }
onConfirm={ this.handleDeleteObject.bind(this, objects[rowIndex].name, hideMe) } // hide after confirmation
close={ hideMe } />
</Modal> }
</Layer>
// this is the toggle for Layer with `id === modalId` can be defined everywhere in the components tree
<LayerContext id={ modalId }> {({showMe}) => // showMe is alias for `show(modalId)`
<div style={styles.iconOverlay} onClick={ (e) => showMe(e) }> // additional arguments can be passed (like event)
<Icon type="trash" />
</div> }
</LayerContext>
</Cell>)
// ...