I've taken next code from here: https://www.meteor.com/tutorials/react/adding-user-accounts.
Can I replace in this particular case
ReactDOM.findDOMNode(this.refs.container)) with
this.refs.container
without any hidden bugs in future?
import React, { Component } from 'react';
import ReactDOM from 'react-dom';
import { Template } from 'meteor/templating';
import { Blaze } from 'meteor/blaze';
export default class AccountsUIWrapper extends Component {
componentDidMount() {
// Use Meteor Blaze to render login buttons
this.view = Blaze.render(Template.loginButtons,
ReactDOM.findDOMNode(this.refs.container));
}
componentWillUnmount() {
// Clean up Blaze view
Blaze.remove(this.view);
}
render() {
// Just render a placeholder container that will be filled in
return <span ref="container" />;
}
}
Or maybe even change using callback function:
....
export default class AccountsUIWrapper extends Component {
componentDidMount() {
// Use Meteor Blaze to render login buttons
this.view = Blaze.render(Template.loginButtons,
this.container);
}
....
render() {
// Just render a placeholder container that will be filled in
return <span ref={(node) => (this.container = node) />;
}
}
As suggested in the react refs documentation
If you worked with React before, you might be familiar with an older
API where the ref attribute is a string, like "textInput", and the DOM
node is accessed as this.refs.textInput. We advise against it because
string refs have some issues, are considered legacy, and are likely to
be removed in one of the future releases. If you're currently using
this.refs.textInput to access refs, we recommend the callback pattern
instead.
Hence ref callback is the right way to go if you want to have future support
export default class AccountsUIWrapper extends Component {
componentDidMount() {
this.view = Blaze.render(Template.loginButtons,
this.container);
}
....
render() {
return <span ref={(node) => (this.container = node) />;
}
}
Related
I got an app that is working on react using a class component, i found a code of a feature that i would like to add to my code but it's made using a functional component. The code is here https://codesandbox.io/s/framer-motion-animate-in-view-gqcc8 but the relevant part is this.
import { useInView } from "react-intersection-observer";
import { motion, useAnimation } from "framer-motion";
import "./styles.css";
function Box() {
const controls = useAnimation();
const [ref, inView] = useInView();
useEffect(() => {
if (inView) {
controls.start("visible");
}
}, [controls, inView]);
I don't know how to add that controls variable in my class component
class App extends Component {
constructor(props) {
super(props);
this.state = {
curtains: null,
loading: true,
renderNav: false
};
}
Should i add it on my state? i don't understand how to make it works in class component
You can't use hooks inside of a class component. What you can do is to write a little wrapper that exposes the ref and controls in a render prop:
const Controls = ({children}) => {
const controls = useAnimation();
const [ref, inView] = useInView();
useEffect(() => {
if (inView) {
controls.start("visible");
}
}, [controls, inView]);
return children(ref, controls);
};
Then you can use it like this:
class App extends Component {
// ...
render() {
return (
<Controls>
{(ref, controls) => (
<motion.div ref={ref} animate={controls}>
{/* content */}
</motion.div>
)}
</Controls>
);
}
}
Lets say you have
const functionalComponent=()=>{
return <h1>Functional componenet</h1>
}
and you want to change it to class component
use this import at the top:
import React,{Component} from "react";
and change your code to something like this:
Class functionalComponent extends Component{
state={}
render(){
return <h1>functional component</h1>;
}
}
your functional component is now changed to class component.
And to use it in your existing class component , you don't need to change your functional component to class component unless you require local state.
with the introduction of react hooks that's also changed i.e, you don't have to change your functional component to class component if you plan to use hooks.
In your code : useEffect is a hook and you can't use it inside a class component.
I would recommend simply importing the functional component inside your class component and if you have to pass some value , you can pass it as a prop.
And as far as importing your functional component is concerned:
import React,{Component} from "react";
import Box from "./Box.js";
class App extends Component {
constructor(props) {
super(props);
this.state = {
curtains: null,
loading: true,
renderNav: false
};
render(){
return(<Box/>);
}
}
You can also use functional components anywhere like a class component. Btw is also using so no need to worry about the thing that you cannot use state in it.
Use:
<Box props={props}/>
Lets say I have a component defined like this -
// actioncomponent.js
import React from 'react';
class ActionComponent extends React.Component {
state = {
isAction: false;
}
doAction = () => {
this.setState({isAction: true})
}
render () {
return (
<div>
Some render stuff..
</div>
)
}
}
export default ActionComponent
From another completely different file I want to set the state for the first component without rendering it in the new file so I need not use refs or props.
// newfile.js
import ActionComponent from './actioncomponent.js'
ActionComponent.doAction()
I'm aware the doAction can't be exported and calling it static doesn't have access to state either. How do I achieve something like this?
In React ecosystem you probably don't need this.
You can pass this method to a child component:
class ActionComponent extends React.Component {
state = {
isAction: false
}
doAction = () => {
this.setState({isAction: true})
}
render () {
return (
<div>
<Child doAction={this.doAction} />
</div>
)
}
}
And then in a Child component you can fire this action
// ...
render() {
<button onClick={() => props.doAction()}>Test</button>
}
If you need to fire action on parent, instead of child you might want to structure your state on upper level, or lift state up.
You can also achieve similar goal without drilling props, but you'll need some state management tool, e.g. Redux or in some cases Context API would be a great fit.
I'm new to React, but not to JS.
Here's a piece of code, that I couldn't understand
// #flow
import React, { Component } from 'react';
import ShowCard from './ShowCard';
import Header from './Header';
class Search extends Component {
state = {
searchTerm: ''
};
props: {
shows: Array<Show>
};
handleSearchTermChange = (event: SyntheticKeyboardEvent & {target: HTMLInputElement}) => {
this.setState({ searchTerm: event.target.value });
};
render() {
return (
<div className="search"></div>
);
}
}
export default Search;
Within the class there are expressions like state = ... and props: {...
Also function definitions like render(){} and handleSearchTermChange = (....
As I recall from all these valid ES6 one is render. How does it work? If I switch the way data assigned to state/props - everything brakes. I assume it's some kind of babel plugin, is it?
Yes, you're right.
The react docs usually defines state via the constructor() {} object. However, in certain projects, we can simply do so via state = {}. This shorthand syntax is possible due to a Babel transpiler called Class properties transform.
Let's say I have two components:
An overlay trigger:
import {openOverlay} from './overlay-actions'
class OverlayTrigger extends Component {
handleMouseOver(event) {
// updates global store
openOverlay({
triggerNode: this.refs.container
})
}
render() {
return <div ref="container" onMouseOver={this.handleMouseOver.bind(this)}></div>;
}
}
// ...map actions to dispatch here
export default OverlayTrigger;
And the overlay container component which gets its props from a parent component that watches a global store for the active overlay definition, which has a triggerNode prop.
class OverlayContainer extends Component {
render() {
return <div></div>;
}
}
OverlayContainer.propTypes = {
triggerNode: PropTypes.node
}
export default OverlayContainer;
The result here is that triggerNode as passed to OverlayContainer is a valid DOM node, but fails the validation by ReactPropTypes' isNode validator. Why? And how can this be resolved?
Use
triggerNode: React.PropTypes.instanceOf(Element)
to verify DOM elements.
I have a page with a form rendered in the server, it handles validation, and the correct value for the selects.
I want to hide the DOM of that form, and append it into a react component so I can use it in react-router.
const NewItem = React.createClass({
render() {
return (
<div>
<h1>New item</h1>
{/* I WANT THE FORM FROM THE PAGE HERE*/}
</div>
)
}
})
What is the best way to do it?
You have full access to the DOM in componentDidMount. You can use refs to access the specific DOM element you want.
var NewItem = React.createClass({
componentDidMount: function () {
this.refs.formTarget.appendChild(myFormDomElement);
},
render: function () {
return React.DOM.div(null,
React.DOM.h1(null, "New item"),
React.DOM.div({ref: "formTarget"}));
}
});
Note that in 0.14, a ref is a raw DOM element. Prior to that a ref was a react component and you had to call React.findDOMNode(it) to get the actual DOM element.
React > 16.3
Try using portals like in this component:
import {Component} from 'react';
import {createPortal} from 'react-dom';
import PropTypes from 'prop-types';
class DOMPortal extends Component {
constructor(props) {
super(props);
this.el = document.createElement(props.component);
}
componentDidMount() {
this.props.parentEl.appendChild(this.el);
}
componentWillUnmount() {
this.props.parentEl.removeChild(this.el);
}
render() {
return createPortal(
this.props.children,
this.el,
);
}
}
DOMPortal.propTypes = {
parentEl: PropTypes.object.isRequired,
component: PropTypes.string,
};
DOMPortal.defaultProps = {
component: 'div',
};
Now you can pass your external DOM reference as the parentEl props to it:
<DOMPortal parentEl={decorator.contentWidget.domNode}>...children</DOMPortal>
React < 16.3
Using this.refs is "deprecated", try this instead :
render() {
return <div ref={(DOMNodeRef) => {
this.componentRef=DOMNodeRef;
}}>
...
</div>;
}
Then this.componentRef will be accesible in componentDidMount() so you can append your external DOM element:
componentDidMount(){
this.componentRef.appendChild(externalDOMelement);
}
Notes:
Remember that this.componentRef changes over time (renders()), so you must update it wherever you are passing it to.
Check for a defined reference before using it: if(this.componentRef){// ... your code}
Functional Components' refs are handled differently.
Source:
React Doc
React gives us the functionality dangerouslySetInnerHTML. it gives us the support of adding HTML element. for example
function createMarkup() {
return {__html: 'First ยท Second'};
}
function MyComponent() {
return <div dangerouslySetInnerHTML={createMarkup()} />;
}
You can also use portals introduced in react-16 for appending React component anywhere in the tree by using following code.
ReactDOM.createPortal(child, container)
follow following link Portals for refference