I know that I can apply motion directly to element/HTMLtag like this:
<motion.div>some content</div>
But how can I apply it to this?
<Comp />
Without wrapping it inside another HTML element, like in React-Transition-Group library.
Framer API provides Frame component, but it acts like permanent additional HTML element with own styling, and it is messing my layout.
If anyone comes to this page seeking for the solution of how to apply motion from Framer-Motion library to your React Component and not the direct DOM element like "div" or "span", here it is:
motion.custom()
Example of use:
import { Link } from "react-router-dom"
const MotionLink = motion.custom(Link)
return <MotionLink />
As for today it is not mentioned in the official documentation, or it is in someplace deep and hard to find.
I had found it in BUG reports here, there is a Codesanbox that illustrates my example, created by the person who reported a bug.
motion.custom was deprecated as of v4.0 in favour of motion(Component) or motion("Component").
Your code would simply look like this
const MotionComp = motion(Comp)
return <MotionComp>some content</MotionComp>
Without using any internal fuctions,
You just need to wrap it with any motion element:
<motion.div>
<Comp />
</motion.div>
You can notice such behavior across examples in the docs, like of Side Menu example.
Related
I'm currently experimenting with React, and I've now run into an issue that I can't seem to solve.
In my application, I use a React library to handle hotkeys, these hotkeys have a scope, so when I want a certain set of hotkeys to be active in a div, I have to wrap that div with a <HotKeys> tag.
I have to toggle some of these divs, so I'll have something along the lines of
isActive ?
<HotKeys ...>
<div ...>...</div>
</HotKeys>
: <div ...>...</div>
I now need to figure out a way to focus the div when it's created. Pretty much every article on the web suggest something like this:
const focusRef = useRef(null);
useEffect(() => {
focusRef.current.focus()
})
return (
isActive ?
<HotKeys ...>
<div ref={focusRef} tabIndex={-1} ...>...</div>
</HotKeys>
: <div ...>...</div>
)
I've tried some variations, including having the div top level (without the <HotKeys> wrapping them), all to no avail.
When I print the focusRef object in the useEffect method, I do get the expected output, focusRef is correctly set and current is populated, but calling the focus method doesn't work. At one point I tried calling the focus method from a button and manually triggering it after the component had fully loaded, it seemed to work (document.activeElement was being changed), then for some reason it stopped working again. All this leads me to believe that somehow the component hasn't fully loaded, despite calling the useEffect hook, which, if I understand correctly, triggers when the element has rendered for the first time/after every change to state.
I'd really appreciate some help with this, since I basically started learning React yesterday.
You must to use an useCallback , because useRef don't notifies you when ref was created
https://reactjs.org/docs/hooks-reference.html#useref
I think I figured it out.
You were right about using the tabIndex but you needed to pass it in as a string like this:
tabIndex={"-1"}
When you first load it a dotted line box surrounds the div that has the ref attached.
check out this code sandbox:
https://codesandbox.io/s/nifty-wildflower-eqjtk?file=/src/App.js
grabbed from this accepted answer where they pass in a string:
Need to put focus on div in react
I am trying to combine Radium and Material-ui. When I try to apply multiple styles on a single Material-ui component, no style is applied. So, for example, something like this produces no styling applied:
<MenuItem style={[styles.styleOne, styles.styleTwo]} >
Of course, if I do something like:
<MenuItem style={Object.assign({}, styles.styleOne, styles.styleTwo)} >
it works. Is there some way around it or this is the only way to use Radium for combining styles for a Material-ui component? And just to mention, Radium is properly set up, because applying array of styles on, for example, DIV element or works properly.
Also, I am open to any suggestion about styling a React project that uses Material-ui library. Thanks!
For material-ui components in react, we add styles using the className. If i have to add multiple styles in a material component then below are the methods:
Example 1:
<div className={`${style1} ${style2}`}>
Example 2:
import classNames from 'classnames';
<div className={classNames(classes.style1, classes.style2)} />
Specifically for your case (Radium):
What it's doing is merging 2 objects (style1 and style2) into a new anonymous object {} which is what you need to do.
You'll want to be careful when doing this however as you'll need to consider how you merge if both objects define the same key e.g. if style1 and style2 both define a height which do you use?
There's a long list of possible ways to do this on this stackoverflow thread http://stackoverflow.com/questions/171251/how-can-i-merge-properties-of-two-javascript-objects-dynamically depending on the libraries you're using and your use case they each have their own pros and cons.
Instead of adding classnames, you can also use the clsx module that comes with Material UI and combine your style classes.
{/* using arrays */}
<MyComponent classes={clsx([classes.text, classes.title])} />
{/* using conditions */}
<div className={clsx(classes.root, {
[classes.base]: true,
[classes.closed]: !open,
[classes.open]: open
})]>
{props.children}
</div>
The Material UI Mini Variant Drawer example does a great job showing this module off.
Check out this fiddle: https://jsfiddle.net/Lxh5x2qr/
It uses the JSX spread (...) operator, which is a bit nicer syntax:
styleOne: {
background: 'blue',
color: 'red'
},
styleTwo: {
background: 'green'
},
... style={{...this.styleOne, ...this.styleTwo}} ...
Please notice the the order of object does matter, just like in Object.assign.
We should not forget that MenuItem is not a DOM element, so when we apply style to it, material-ui manipulates it before applying it to the underlying element, and probably this is the reason why using an array does not work.
I've watched,
http://youtu.be/z5e7kWSHWTg?t=15m17s
and read,
https://github.com/ryanflorence/react-training/blob/gh-pages/lessons/05-wrapping-dom-libs.md
https://github.com/ryanflorence/react-training/tree/gh-pages/code/Dialog
http://jsbin.com/dutuqimawo/edit?js,output
How to create a React Modal(which is append to `<body>`) with transitions?
and I get the concept of the Portal, that you're tricking React into ceasing its rendering for one piece of the DOM, then continuing the rendering afterward, so you can tinker with that piece of the DOM without confusing React by making its virtual DOM get out of sync.
My problem is that the examples all address a Dialog that is rendered at the end of the page, but appears inline when you're reviewing your code. It's a cool trick for using a jQuery modal, but I need a jQuery datepicker whose div actually remains where I put it. (As an aside, I'm also curious about GetDOMNode's presence in the examples when it's deprecated? I suppose you use FindDOMNode, although you call it slightly differently, plus the documentation says "In most cases, use of this escape hatch is discouraged because it pierces the component abstraction", which makes me a little gunshy to use it.)
To isolate the jQuery datepicker from React, I originally created one React component to handle everything above the datepicker, and another to handle everything below the datepicker, and used event listeners in each component to listen for updates. However, I prefer the design of a single parent component that passes everything down to its children; it seems like a cleaner design.
I redesigned it with a single parent and it seems to work, but I have no idea if my portal is really isolated from React's virtual DOM or not; it's my first crack at a portal so I'm really muddling through. (I am using React-Bootstrap for my navbar and it works great; I just couldn't find an equivalent to jQuery's datepicker and I like how it looks and operates, which is why I'm sticking with it.)
Here's my top-level component (I removed the props/componentDidMount/etc for clarity). The <CalendarControl /> is going to be the portal:
var ReactApp = React.createClass({
render: function() {
return (
<div>
<BootstrapNavbar division={this.state.division} dps={this.state.dps} sections={this.state.sections} />
<div className="container">
<br />
<br />
<br />
<div className="row">
<div className="col-md-4" id="calendarPortal">
<CalendarControl />
</div>
<div className="col-md-8">
<h3>{this.state.dp}</h3>
<h4>{this.state.dpStartDate} - {this.state.dpEndDate}</h4>
</div>
</div>
<TimebookTableRecords timebookRecords={this.state.timebookRecs} />
</div>
</div>
);
}
});
Here's the code for my CalendarControl portal. When the CalendarControl mounts, I'm creating a new div calendarControl as a child of calendarPortal. I then use jQuery to create the datepicker on the calendarControl div.
var CalendarControl = React.createClass({
render: function () {
return null;
},
componentDidMount() {
var portalLocation = document.getElementById("calendarPortal");
var newElement = document.createElement('div');
newElement.id = "calendarControl";
portalLocation.appendChild(newElement);
},
componentWillUnmount() {
var portalLocation = document.getElementById("calendarPortal");
document.body.removeChild(portalLocation);
},
});
Here's the jQuery code that creates a datepicker on the calendarControl div:
$("#calendarControl").datepicker({
numberOfMonths: monthDiff,
defaultDate: dpStartDate,
showButtonPanel: false,
beforeShowDay: formatCalendarDays, //formatter function
onSelect: dateClicked //handles click on calendar date
The final product seems to work fine, and doesn't generate any "the DOM was unexpectedly mutated" errors like when you manipulate part of the DOM that's under React's purview. I can update the state of the parent and see the changes propagate down nicely, and use jQuery to update the calendar.
However, I just don't know if this is the correct approach? That is to say, have I achieved a true portal here? I used the Google Chrome React Developer Tools add-in to inspect the component hierarchy, and it does look like from React's perspective there's a null in the CalendarControl div:
Thanks for bearing with me in this lengthy post. I have to say that so far I'm really loving the React approach to web development; it's so radically different that it took a number of readings and tinkering just to understand its concepts, but now it seems so much more elegant than the ways I've done it in the past.
From my understanding of portals, you are doing this mostly correct. But if it had any other children, you would have to reconnect with react after the jquery stuff, but I assume that is not the case here.
The reason you are seeing a "null" inside calendar control is because you return a null in your CalendarControl render function.
Why don't you just change your render function in calendarControl to:
render: function () {
return (
<div id="calendarControl"></div>
)
and do all your funky jQuery rendering inside componentDidMount function?
folks. I'm a relatively new Meteor developer, and after learning Blaze, I decided to start learning React, because it seemed like the right thing to do, and I sort of liked the idea of how it worked.
Anyway, I'm having issues with a bit of code I'm working on, and could use some guidance... I've got the following segments of code:
https://gist.github.com/czbaker/2101526219eea5330553
For some reason, when the form in the component is submitted, it isn't firing the function that's meant to handle submission. Instead, it refreshes the page (as event.preventDefault() never happens).
What would be causing this to happen? As per suggested on IRC, I've tried replacing onSubmit={this.handleSubmit} with the following:
onSubmit={()=>{this.handleSubmit}}
onSubmit={this.handleSubmit()}
Neither of them had any effect, the form submission function still isn't being called. I'm really confused, because I followed documentation for the most part, and it looks like it should be working.
As I'm really new to React, I'm sure I'm overlooking something, but have no idea what. Can anyone offer me some aid? Thanks in advance!
The current project is also in a BitBucket repository, for those who need it https://bitbucket.org/czbaker/karuto/
All I've been able to figure out so far is that if I render the problem component by itself (not as a child of another component) using ReactLayout, it works fine, but the second that I try to render it as a child component (doing it the way it's shown in MDG's Todos tutorial (React version), events refuse to fire, yet there's no errors.
Thanks in advance for help.
The problem is you are attempting to render the entire HTML tree using React.
If you are using flow-router and react-layout, you can simply render the document fragment that you desire and it will be placed in a designated root node which id is 'react-root'.
Otherwise, I would suggest using static-html if you don't need blaze and create a root element for React:
some_file.html:
<body>
<div id="react-container"></div>
</body>
and then render the root component into it using your preferred router.
Then, change the title dynamically via a ReactiveVar or some other method.
I am using React with React Router, alongside Google's MDL, and had the same issue (as well as a few others, such as navigating to different routes would cause a full page reload).
When attempting to find the cause, I found that removing the MDL classes from the the div surrounding {this.props.children} in my parent component resulted in the event listeners firing correctly.
After investigating, it appears that this is due to the way that MDL structures the DOM nodes, and can be resolved by either calling componentHandler.upgradeDOM() in each child component's componentDidUpdate() method, as follows:
App = React.createClass({
render() {
return(
<div className="mdl-layout mdl-js-layout">
...
<div className="mdl-layout__content">
{ this.props.children }
</div>
</div>
);
}
});
ChildComponent = React.createClass({
handleClick() {
alert("I've been clicked!");
},
render() {
return(
<div>
<button onClick={this.handleClick}
className="mdl-button mdl-js-button">Click Me</button>
</div>
);
},
componentDidUpdate() {
componentHandler.upgradeDOM();
},
});
As outlined here, http://quaintous.com/2015/07/09/react-components-with-mdl/; or by using a 'patched' version of MDL, like the one here:
https://github.com/tleunen/react-mdl
I know this is a little different to the OP's issue, but I figured I'd add this here in the hopes that it helps someone else with this issue. :)
In my Layout.jsx i changed
export default class extends React.Component {
render() {
return(
<body>
...some jsx
</body>
);
}
}
to
export default class extends React.Component {
render() {
return(
<div>
...some jsx
</div>
);
}
}
and it helps, now the React events are working fine
Before anyone press eagerly the close button, I already have looked the following question: ReactJS Two components communicating. My problem is exactly the third scenario developped in the current accepted answer.
I am using ReactJS to build something with two components. For HTML reasons (and presentation), i want my two components to be at two different places of the page.
For the moment, I have the following pattern, corresponding to scenario #2:
FooForm = React.createClass({
...
});
FooList = React.createClass({
...
});
FooManager = React.createClass({
...
render: function () {
return (
<div>
<FooForm ref="form" manager={this} />
<FooList ref="list" />
</div>
);
}
});
React.render(
<FooManager someProp={value} />,
document.getElementById('foo')
);
This gives something like:
<div id="foo">
<form>Form generated with the render of FooForm</form>
<ul>List generated with the render of FooList</ul>
</div>
However, i would like to have something like this:
<div id="fooform">
<form>Form generated with the render of FooForm</form>
</div>
<!-- Some HTML + other controls. Whatever I want in fact -->
<div>...</div>
<div id="foolist">
<ul>List generated with the render of FooList</ul>
</div>
The problem here is: how can I keep a reference in each component? Or at least the link Form -> List?
I tried to create the FooList before and pass the reference to the current manager, but I get the following warning/error:
Error: Invariant Violation: addComponentAsRefTo(...): Only a ReactOwner can have refs. This usually means that you're trying to add a ref to a component that doesn't have an owner (that is, was not created inside of another component's `render` method). Try rendering this component inside of a new top-level component which will hold the ref.
The documentation says you can attach events to link two components which do not have a parent-child relation. But I don't see how. Can someone give me some pointers?
The Less Simple Communication lesson from react-training has a good example of how you can move actions & state sideways to avoid having to create an explicit link between related components.
You don't need to jump into a full Flux implementation to get the benefit of this approach, but it's a good example to lead you up to Flux, should you eventually need it or something like it.
Note that this requires you to model the relationship between the components based on changing state rather than explicitly passing a reference to a component instance (as you're doing above) or a callback bound to the component managing the state.
This would be the perfect use-case for a Flux type architecture.
What you want is someone FooManager to be able to trigger state changes in both components. Or, in fact, having the different components trigger, through Actions, state changes in each other.
The Flux Todo-App Tutorial illustrates your use-case perfectly!
After this, then you'd have the choices of using Facebooks implementation of Flux or the other gazillion ones.
My personal favorite is Reflux