The Minimum Town


Why Do React Elements Have a? typeof Property?

December 10, 2018

Why do React Elements need one? Typeof attribute?

Translated from Dan Abramov’s blog

When writing JSX, you might feel like you’re just writing:

<marquee bgcolor="#ffa7c4">h1</marquee>Copy the code

Instead, you are calling a method:

React.createElement(
  /* type */ 'marquee',
  /* props */ { bgcolor: '#ffa7c4' },
  /* children */ 'hi'
)Copy the code

This method will return you an object. We call this object the React element. It tells React how to render next. Your component returns a tree structure based on this object.

{ type: 'marquee', props: { bgcolor: '#ffa7c4', children: 'hi' }, key: null, ref: null, ? Typeof: Symbol. For ('react.element'), // 🧐 Who dis}Copy the code

If you’ve used React, you’re familiar with types, props, keys, and refs. But what is? Typeof? Why is it a Symbol() value?

Actually, this question belongs to the “React you don’t need to know” series, but it can improve your happiness in coding. This article also contains some security tips you may be wondering about. Maybe one day you’ll write your own UI library, and this knowledge will come in handy. This is what I sincerely want.


Before client-side UI libraries were ubiquitous and had some basic protections, we would typically construct an HTML structure and insert it into the DOM:

const messageEl = document.getElementById('message');
messageEl.innerHTML = '<p>' + message.text + '</p>';Copy the code

This seems fine, unless your message.text is something like . You don’t want things written by strangers printed word for word line by line in your HTML.

(Fun fact: JavaScript code in this form of

You can defend against such injection attacks with solid apis such as Document.createTextNode () or textContent, which only generate plain text nodes. You can also “escape” user input, pre-emptively replacing <, > or other user-supplied text with safe characters.

Still, this doesn’t seem like enough, and keep in mind that escaping every time the user input is output is a hassle, and that a single slip can lead to an error, which can be very expensive. This is why modern lib defaults to escape text content such as React.

<p>
  {message.text}
</p>Copy the code

If message.text is a malicious string containing tags such as , those tags will not be rendered as real HTML nodes. React avoids such unreliable content and inserts the processed data into the DOM. So you’ll only see the text tag of < IMG > or some other tag, not the corresponding HTML node.

To render an arbitrary HTML string in the React Element, you need to use dangerouslySetInnerHTML={{__html: message.text}}. In fact, this feature is pretty clunky. The point is to improve the visibility of related features during code review or code review.


Does React completely defend against injection attacks? Not at all. HTML and DOM provide a lot of vulnerable interfaces that React or other UI libraries can’t handle. Most of these attacks are attribute-oriented. For example, if you render a < a href = {user. Website} > such labels, have to be wary of encounter ‘javascript: stealYourPassword ()’ such a user page. Or, like

This practice of expanding user input is rare, but equally unreliable.

React can provide more protection as technology evolves, but many of these problems come from the server side and should be addressed there.

Of course, escaping text content is still the first dogma of defense against potential intrusions. Isn’t it nice to be comfortable with code like this? ~

<p> {message.text} </p>Copy the code

Not always, though. This is what? The reason typeof appears.


The React element is essentially a pure object:

{ type: 'marquee', props: { bgcolor: '#ffa7c4', children: 'hi' }, key: null, ref: null, ? typeof: Symbol.for('react.element') }Copy the code

React exactly provides a way to create elements using the above pure object approach. Normally, you can create them with react.createElement (), but this is optional. Of course, you don’t want to write code like this — but it’s useful for optimizing UI object passing between compilers and workers. You can’t use JSX in Webworker) or decouple JSX from the React code package.

However, if your server has a bug that allows the user to store arbitrary JSON objects, but the client needs a string value, this could be a problem:

// Server could have a hole that lets user store JSON
let expectedTextButGotJSON = {
  type: 'div',
  props: {
    dangerouslySetInnerHTML: {
      __html: '/* put your exploit here */'
    },
  },
  // ...
};
let message = { text: expectedTextButGotJSON };

// Dangerous in React 0.13
<p>
  {message.text}
</p>Copy the code

In the case of this XSS injection attack, React 0.13 would be vulnerable. Again, this attack relies on a server-side vulnerability. React still does something better to avoid this problem. Starting with 0.14, React did it.

React 0.14 addresses this problem by marking each React element with a Symbol attribute of type:

{ type: 'marquee', props: { bgcolor: '#ffa7c4', children: 'hi' }, key: null, ref: null, ? typeof: Symbol.for('react.element') }Copy the code

This works by taking advantage of the fact that the JSON attribute value cannot be Symbol. Even if the server has a security flaw that returns JSON instead of plain text, the value of the property in JSON cannot be symbol.for (‘ react.element ‘). React checks element.? Typeof, and avoids elements that have lost this attribute or whose attribute checks fail.

The advantage of symbol.for () is that Symbols are very global, so you can use symbol.for () to query the corresponding rules in some special environments, such as iframe or webworker contexts. Thus, even in very specific situations, different parts of the application can smoothly deliver reliable elements. Similarly, even if there are multiple copies of React instances on the same page, they can be stored in? “Consensus” on the Typeof attribute.


What if the browser doesn’t support the Symbol type?

Alas, they don’t get this particular protection. But React will still be defined in elements for consistency, okay? Typeof property, except that it will be set to a value of type number — 0xeAC7.

Why this particular number? Because 0xeAC7 looks a bit like “React.”


  • ← Understand state management from the perspective of human behavior