There are different reasons behind it, but I wonder how to simply add custom attributes to an element in JSX?
EDIT: Updated to reflect React 16
Custom attributes are supported natively in React 16. This means that adding a custom attribute to an element is now as simple as adding it to a render function, like so:
render() {
return (
<div custom-attribute="some-value" />
);
}
For more:
https://reactjs.org/blog/2017/09/26/react-v16.0.html#support-for-custom-dom-attributes
https://facebook.github.io/react/blog/2017/09/08/dom-attributes-in-react-16.html
Previous answer (React 15 and earlier)
Custom attributes are currently not supported. See this open issue for more info: https://github.com/facebook/react/issues/140
As a workaround, you can do something like this in componentDidMount:
componentDidMount: function() {
var element = ReactDOM.findDOMNode(this.refs.test);
element.setAttribute('custom-attribute', 'some value');
}
See https://jsfiddle.net/peterjmag/kysymow0/ for a working example. (Inspired by syranide's suggestion in this comment.)
You can add an attribute using ES6 spread operator, e.g.
let myAttr = {'data-attr': 'value'}
and in render method:
<MyComponent {...myAttr} />
Consider you want to pass a custom attribute named myAttr with value myValue, this will work:
<MyComponent data-myAttr={myValue} />
You can use the "is" attribute to disable the React attribute whitelist for an element.
See my anwser here:
Stackoverflow
if you are using es6 this should work:
<input {...{ "customattribute": "somevalue" }} />
I ran into this problem a lot when attempting to use SVG with react.
I ended up using quite a dirty fix, but it's useful to know this option existed. Below I allow the use of the vector-effect attribute on SVG elements.
import SVGDOMPropertyConfig from 'react/lib/SVGDOMPropertyConfig.js';
import DOMProperty from 'react/lib/DOMProperty.js';
SVGDOMPropertyConfig.Properties.vectorEffect = DOMProperty.injection.MUST_USE_ATTRIBUTE;
SVGDOMPropertyConfig.DOMAttributeNames.vectorEffect = 'vector-effect';
As long as this is included/imported before you start using react, it should work.
See attribute value in console on click event
//...
alertMessage (cEvent){
console.log(cEvent.target.getAttribute('customEvent')); /*display attribute value */
}
//...
simple add customAttribute as your wish in render method
render(){
return <div>
//..
<button customAttribute="My Custom Event Message" onClick={this.alertMessage.bind(this) } >Click Me</button>
</div>
}
//...
Depending on what version of React you are using, you may need to use something like this. I know Facebook is thinking about deprecating string refs in the somewhat near future.
var Hello = React.createClass({
componentDidMount: function() {
ReactDOM.findDOMNode(this.test).setAttribute('custom-attribute', 'some value');
},
render: function() {
return <div>
<span ref={(ref) => this.test = ref}>Element with a custom attribute</span>
</div>;
}
});
React.render(<Hello />, document.getElementById('container'));
Facebook's ref documentation
uniqueId is custom attribute.
<a {...{ "uniqueId": `${item.File.UniqueId}` }} href={item.File.ServerRelativeUrl} target='_blank'>{item.File.Name}</a>
Depending on what exactly is preventing you from doing this, there's another option that requires no changes to your current implementation. You should be able to augment React in your project with a .ts or .d.ts file (not sure which) at project root. It would look something like this:
declare module 'react' {
interface HTMLAttributes<T> extends React.DOMAttributes<T> {
'custom-attribute'?: string; // or 'some-value' | 'another-value'
}
}
Another possibility is the following:
declare namespace JSX {
interface IntrinsicElements {
[elemName: string]: any;
}
}
See JSX | Type Checking
You might even have to wrap that in a declare global {. I haven't landed on a final solution yet.
See also: How do I add attributes to existing HTML elements in TypeScript/JSX?
For any custom attributes I use react-any-attr package
https://www.npmjs.com/package/react-any-attr
Related
This is somewhat of weird question. I'm working with event types in React, and we want to use onClick in some instances, and onPointerDownCapture in others (for reasons). But to make this more general, it could be any two different click-like events. The issue is that while we can assign whatever function handler on the right side of the expression, the left side has to be static, essentially. So,
<button
onClick={handler} vs onPointerDownCapture={handler} vs onMouseDown={handler}
/>
I think just using onPointerDownCapture will be fine for most usecases, but in a perfect world, I'd be able to flip between these at runtime based on other variables. Is it possible to override the onClick on the button/div/whatever prototype or something to be whatever event type I want it to be?
Much googling. No success.
I didn’t fully understand what you mean by “overriding onClick”, but
The issue is that while we can assign whatever function handler on the right side of the expression, the left side has to be static, essentially.
This is not true, left hand side could be dynamic, here’s how:
<button {...({ [eventName]: handler })} />
I guess this solves your problem.
Ok above syntax is a bit terse and admittedly confusing. It’s the good old JSX spread props syntax, just over an inline object literal.
I’ll give you another equivalent form, hopefully it should be more readable.
const eventName = someCondition ? "onPointerDownCapture" : "onClick"
const props = {
[eventName]: handler
}
<button {...props} />
You have to use those attribute names and you use the same function name for all 3 of them.
What these 3 attributes do is they register the associated event.
Maybe you could use a useEffect and add there conditionally an event listener instead of the proposed React attributes.
I think best is #vera solution in comment. Pass extra prop to component (for example isOnClick), and based on it pass either callback or undefined to event handler prop:
function Component(props: { isOnClick: boolean; callback: () => void }) {
return (
<div
onClick={props.isOnClick ? props.callback : undefined}
onMouseDown={props.isOnClick ? undefined : props.callback}
/>
);
}
Note that passing undefined to prop is same as not setting that prop.
Alternatively conditionaly return component:
function Component(props: { isOnClick: boolean; callback: () => void }) {
if (props.isOnClick) {
return <div onClick={props.callback}/>
} else {
return <div onMouseDown={props.callback}/>
};
}
What are the use cases which require the use of the HTML attribute ref?
And what would be the value affected to it?
I've faced this example:
methods: {
myMethod(event) {
this.$refs.userInfo.open();
},
}
<template>
<myComponent
ref="userInfo"
:usr="usr" />
</template>
So my question what is userInfo really is?
From where comes open method ?
Template refs is a way of accessing the element itself in the DOM.
It's usually used to make some DOM-specific things or to handle some edge-cases (like a vanilla JS package not fully compatible with Vue's reactivity).
If not needed, you could use regular event listeners + iterations with v-fors.
In your given example, you're accessing either a component userInfo or a method/object with a public method of open. I recommend that you inspect your DOM tree in your Vue devtools.
Description
I'm struggling to add the type annotation of a useRef attached on this player component: react-player to get access to the seekTo instance method as per the documentation demo source code. I can't seem to get the type to work - I'm kinda new to typescript and probably going about this wrong so any pointers would be helpful! I've looked at the react-player index.d.ts and can see the function is listed there, just need to know how I'm supposed to be writing this in.
Expected Behavior
Have access to the instance methods of the player.
Error
Property 'seekTo' does not exist on type 'MutableRefObject<ReactPlayer | null>'.ts(2339)
Steps to Reproduce
I made a small codeSandbox - basically trying to mimic the demo source for adding a ref to utilise the seekTo method onMouseUp on a range type input.
https://codesandbox.io/s/react-typescript-lqgvr?file=/src/index.tsx
Thanks!
A few things regarding your code:
To access a ref, use ref.current instead of ref..
The ref can be null, so you have to check if it is null
Use currentTarget of the event to access the value instead of target.
onMouseUp={(e) => {
if (player.current) {
player.current.seekTo(parseFloat(e.currentTarget.value));
}
}}
I'm on a project using TS with React. I was able to get everything working by declaring:
const player = useRef<ReactPlayer>(null);
And then in my :
<ReactPlayer ref={player} />
So any time I need to use a function like seekTo() it looks like:
player?.current?.seekTo(seconds);
No need to use:
import { BaseReactPlayerProps } from 'react-player/base';
I have been struggling with this too.
import { BaseReactPlayerProps } from 'react-player/base';
const MyPlayer = ({playerRef : BaseReactPlayerProps}) => {
// component code
if (playerRef) {
currentPlayerRef.seekTo(seconds, 'fraction');
}
}
I am getting confused with props and refs in ReactJS. Can anybody explain me the difference between them with proper example.
Thanks in advance.
Props are used to pass parameters which should be static (on the contrary of state). For example you can pass a size or name from an upperView to a lowerView (nested views);
Interesting part on props: https://facebook.github.io/react/docs/transferring-props.html
refs are used to acces the real DOM and not the virtual DOM of react. It's needed when you need to access the real DOM.
This part is interesting :https://facebook.github.io/react/docs/more-about-refs.html
this.setState({userInput: ''}, function() {
// This code executes after the component is re-rendered
React.findDOMNode(this.refs.theInput).focus(); // Boom! Focused!
});
The example above show you how to access a DOM element properly when the state is updated.
Hope it helps.
For sure there are differences between, one mostly use for selecting the DOM, one for getting data as a property, I create the image below and explain few major differences:
Also this the sample of grandparent, parent and child components which using ref and props to pass data, it's a good example to understand when and how they get used, please pay attention how ref helping to get in deeper component by referencing to the element:
function Child(props) {
return (
<div>
<input ref={props.inputRef} />
</div>
);
}
function Parent(props) {
return (
<div>
My input: <Child inputRef={props.inputRef} />
</div>
);
}
class Grandparent extends React.Component {
render() {
return (
<Parent
inputRef={el => this.inputElement = el}
/>
);
}
}
Those are two different things.
Props: Use them to pass any parameters to your component.
Refs: Shortcut for references. These are references to your DOM elements. Use them if you need to access raw DOM element for some reason. For example to add custom event handler via .addEventListener() function.
in addition to the answer above by François Richard, u might wanna read:
https://github.com/uberVU/react-guide/blob/master/props-vs-state.md
because the confusion is more often between state and props.
good luck
I am struggling to use refs in React. They always return root DOM node of the component instead of reffed one.
Please consider the following example:
var AuthApp = React.createClass({
onSubmitClick: function(event) {
var usernameInput = this.getDOMNode(this.refs.username);
// This logs root <div> instead of <input>, why???
console.log(usernameInput);
},
render: function() {
return (
<div>
<input type="text" ref="username"/>
<input type="password" ref="password"/>
<input type="submit" onClick={this.onSubmitClick} />
</div>
);
}
});
I've inspected the code in excellent Chrome React addon, and it seems that this.refs.username properly reflects <input> tag:
Something wrong happens when I call this.getDOMNode - it returns root <div> specified in render() instead of <input>.
This code comes from React 0.12, but I've tried to do the same on 0.13 (I am aware of change to React.findDOMNode()) and I get the same result.
What am I doing wrong?
You should be using
var usernameInput = React.findDOMNode(this.refs.username);
to get a reference to the component's DOM node using refs.
The getDOMNode method has been deprecated
getDOMNode is deprecated and has been replaced with
React.findDOMNode().
You should use this.refs['username'].getDOMNode(). But maybe in newer versions of React you better use React.findDOMNode, as adeneo adviced.
To expand on adeneo's answer, instead of doing React.findDOMNode(this.refs.username) you can simply do this.refs.username because the ref that is returned is the DOM Node.
See this link for the reference:
https://facebook.github.io/react/blog/2015/10/07/react-v0.14.html#dom-node-refs