React components rendering with variable names - reactjs

I have a unknown list of react components to render.
// this is a react component
var DefaultModule = require('./DefaultModule.js');
<DefaultModule/> <--- this will output something because the name is
exactly the class name inside DefaultModule.js
but if I do
// this is a react component
var sssss = require('./DefaultModule.js');
<sssss/> <--- this will not work
so is there a way I can take a list of component names and render them accordingly? Thanks.
p.s: the react component looks like this
import React, {PropTypes, Component} from 'react';
class TestComponent extends Component {
render() {
return (
<div>
1123123123123123 hahaha small test
</div>
);
}
}
export default TestComponent;

I just figured out the answer from a discussion thread...
Yes I can do that but the react component must start in capital letter. so Sssss will work sssss will now.
https://github.com/facebook/react/issues/3365
The key is to use a capitalized variable name (Component) otherwise React will treat it as a built-in DOM element.

Related

How to wrap ALL components of react in a HOC?

ReactJS is a great library, However, it misses some features which I found in Vue and Angular. These features can be implemented of course in React, however, they require extra code to be written.
Every react component, or every JSX element I should say has the following properties shared, which are given by React to us to consume:
ref
key
I wanted to add extra props:
renderIf
fallback
These props help in a way I can't describe when it comes to conditional rendering and filtering the views based on the logged-in user permissions and roles (and other conditional rendering use cases, of course).
In react, if we wanted to apply these props to our components, we would use a HOC as follows:
// 🍎 Disclaimer: you don't have to understand any of the code written bellow, the general idea is that this is a HOC.
import React from 'react'
import getVal from './getVal'
export default function EnhancedComponent(OriginalComponent) {
return ({ renderIf: renderIf_ = true, override: override_, fallback: fallback_ = undefined, ...props }) => {
const renderIf = getVal(renderIf_)
const override = getVal(override_)
const fallback = getVal(fallback_)
const consumersComponent = <OriginalComponent {...props} />
let render = fallback
if (renderIf) render = consumersComponent
if (override_ !== undefined) render = override
return render
}
}
Where every time you want to apply these props to your components, you would have to wrap every new component you create with EnhancedComponent as follows:
export default EnhancedComponent(function Sidenav(){
return <div> side nav </div>
})
Now, you can use your Sidenav component within your App component as follows:
import Sidenav from './Sidenav'
export default function App(){
return (
<div>
<Sidenav renderIf={(5 + 5 === 10)}/>
<div>etc</div>
</div>
)
}
This API is great, but it has a drawback, which is, every time you want to apply these cool props (renderIf and fallback) you'll have to repeat these steps:
import Enhanced component to your file.
wrap your export with Enhanced component.
What I am looking for, is a method, or a way to inherit, or to add some props to the original react component class, somehow?
In react class components, I can imagine doing this on the React.Component class which we used to extend from in the past
class Car extends React.Component{
constructor(){}
render(){
return <div>I miss you 🌹</div>
}
}
But in react functional component, how can we do that?
I want to apply these props by default everytime I create a new component, without wrapping my components in a HOC everytime.
Does React have a way to do that? To change its defaults ?

React - Component not updating after props change

I have a very simple react component to show FontAwesome Icons. It looks like this:
import React from 'react';
export default class FasIcon extends React.Component {
constructor(props) {
super(props);
}
render() {
console.log("rendering FasIcon ");
const spanClass = ["icon is-", this.props.size, " is-", this.props.side].join("");
let component = "";
if (this.props.icon) {
component = (
<span className={spanClass}>
<i className={["fas fa-", this.props.icon].join("")} />
</span>
);
}
return component;
}
}
I am using this on an email field that does email validation:
Initially the prop icon is empty. This works.
When starting to check if the address is used (an async server call) I update the icon to a value spinner and the icon displays correctly.
When the check is completed i plan to change it to either times or check. This is correctly reflected in the props in the React Dev Tools, but it is not reflected in the actual site.
Update
The issue was that I was importing the svg library which substituted the icon element for an svg. Once the SVG was placed, react was not able to substitute the icon in the DOM.
I've used the fortawesome prerelease plugins for react and it now works.
The render method was correctly called at all times.
To fix this you have to add a key prop to the i tag like this:
<i key={this.props.icon} className={["fas fa-", this.props.icon].join("")} />

Cannot create an element in react component dynamically

Im not able to create a React component dynamically.
I see blank page with no errors with below code.
1) Trying to create an element named "PieChart"
2) Below are the Two errors im seeing in console.
1. Warning: <PieChart /> is using incorrect casing. Use PascalCase for
React components, or lowercase for HTML elements.
2. Warning: The tag <PieChart/> is unrecognized in this browser. If you
meant to render a React component, start its name with an
uppercase letter.
3) Im Already using Pascal case "PieChart"
import PieChart from "../component/PieChart";
class App extends Component {
render() {
const GraphWidget = React.createElement("PieChart");
return (
<div>
{GraphWidget}
</div>
)
}
}
export default App;
From the createElement documentation:
Create and return a new React element of the given type. The type argument can be either a tag name string (such as 'div' or 'span'), a React component type (a class or a function), or a React fragment type.
You are trying to use a React component type therefore you cannot use a string, you need to use the class directly:
const GraphWidget = React.createElement(PieChart);
If your aim is to map strings to components, you can create simple mapping using a dictionary:
const components = {
PieChart: PieChart
...
};
const GraphWidget = React.createElement(components['PieChart']);
You should user **PascalCase** Naming conventions.
For Example,
class StudentGrades extends Component{
// Your Stuff
}
the component you created should start with Capital latter and using
this within JSX also written with the same name
class TodoItem extends React.Component {
render(){
return <TodoItem>
}
this could be the one of the issue

Lint complains about missing prop coming from HOC

I'm using the package react-translate to localise my app.
import React from 'react';
import { translate } from 'react-translate';
class Hello extends React.Component {
render() {
return (
<div>
{this.props.t('test_string')}
</div>
);
}
}
export default translate('Hello')(Hello);
In the snippet above, translate is a High Order Component, that adds the function t to the properties of Hello.
Everything works fine but lint keeps complaining because t is not in the propTypes.
error 't' is missing in props validation react/prop-types
Is that normal? I guess I'm doing something wrong but I cannot tell what...
Edit:
As #stevejay says, I could add the t to my propTypes but I don't like this solution because - from my total ignorance in react - 1) t is not a property of the component itself, nor something I want to manually pass and 2) I have to add the property to all the models where I have already added the HOC and it seems redundant
To silence the linter, you need to just add propTypes to your Hello component:
import React from 'react';
import PropTypes from 'prop-types';
import { translate } from 'react-translate';
class Hello extends React.Component {
...
}
Hello.propTypes = {
t: PropTypes.func.isRequired
}
Any props that a component you create uses should be declared in that way.

How to render a reactjs component stored in a redux reducer?

I have a redux reducer loaded with several reactjs components.
I want to load these inside other components through this.props
Like: this.props.components.MyReactComponent
class OtherComponent extends Component {
render() {
const Component = this.props.components.MyReactComponent
return (
<div>
<Component />
</div>
)
}
}
Is this possible? If so, how?
EDIT The component is a connected component. I am able to load it but it is broken. In this case, it is a counter, when you click to increment or decrement nothing happens. In the console, there is this error:
Uncaught ReferenceError: _classCallCheck is not defined
if I convert the component into a dumb component (without connecting it), the error is this:
Uncaught ReferenceError: _classCallCheck3 is not defined
EDIT 2
I found out why those errors show up. It is because the react component gets stripped out when stored in the reducer:
A react component would look something like this:
{ function:
{ [Function: Connect]
displayName: 'Connect(Counter)',
WrappedComponent: { [Function: Counter] propTypes: [Object] },
contextTypes: { store: [Object] },
propTypes: { store: [Object] } } }
However, after I store it inside a reducer, it loses its properties and ends up looking something like this:
{ function:
{ [Function: Connect] } }
After reading the comments below, I thought of an alternative. I can store in a reducer the path to each component, then make a new wrapper component that could render those other components from those paths.
I tried it but encoutered a different problem with the funcion require from nodejs that for some weird reason is not letting me user a variable as an argument. For example:
This works:
var SomeContent = require('../extensions/myContent/containers')
This does not:
var testpath = '../extensions/myContent/containers'
var SomeContent = require(testpath)
Giving me the following error:
Uncaught Error: Cannot find module '../extensions/myContent/containers'.
It is adding a period at the end of the path. How can I prevent require to add that period?
If you can think of any other alternative I can implement for what I am trying to do, I would greatly appreciate it.
EDIT 3 Following Thomas advice...
What I am trying to accomplish is this:
I want to be able to render react components inside other react components, I know how to do it the same way most us know how to; however, I want to be able to do it by importing a file that would contain all the components without actually having to import and export each one of them:
OtherComponent.js
import React, { Component } from 'react'
import { SomeComponent } from '../allComponentes/index.js'
export default class OtherComponent extends Component {
render() {
return (
<SomeComponent />
)
}
}
SomeComponent.js
import React, { Component } from 'react'
export default class SomeComponent extends Component {
render() {
return (
<div>
Hello
</div>
)
}
}
allComponents/index.js
import SomeComponent from '../allComponents/SomeComponent/index.js'
export { SomeComponent }
What I am trying to do in allComponents/index.js is to avoid having import/export statements for each component by reading (with fs module) all the components inside the allComponents folder and export them.
allComponents/index.js (pseudocode)
get all folders inside allComponents folder
loop through each folder and require the components
store each component inside an object
export object
When I tried that, I encountered multiple issues, for one, export statements have to be in the top-level, and second, fs would work only on the server side.
So, that is why I thought of loading all the components in a reducer and then pass them as props. But as I found out, they got stripped out when stored them in a reducer.
Then, I thought of only storing the path to those components inside a reducer and have a wrapper component that would use that path to require the needed component. This method almost worked out but the nodejs function require wont allow me to pass a variable as an argument (as shown in EDIT 2)
I think your question is not really to do with redux but rather is (as you say):
What I am trying to do in allComponents/index.js is to avoid having import/export statements for each component by reading (with fs module) all the components inside the allComponents folder and export them.
By way of example, I have all of my (dumb) form components in a folder path components/form-components and the index.js looks something like:
export FieldSet from './FieldSet'
export Input from './Input'
export Label from './Label'
export Submit from './Submit'
export Select from './Select'
export Textarea from './Textarea'
Then when I want to import a component elsewhere, it is import { FieldSet, Label, Input, Submit } from '../../components/form-components/';

Resources