Calling dynamic component in React JS - javascript

I am new in react JS. I am calling a react component from a HTML string which is coming from another javascript class. But the component is not rendering on the screen.
class Form extends Component {
render() {
var markup = '<Sections />';
return (<div className="content" dangerouslySetInnerHTML={{__html: markup}}></div>);
}
}
class Sections extends Component{
render(){
return (<div className='row'>Row1</div>);
}
}
Please help me where am i going wrong.
I think the reactjs is not recognizing the sections component as it is coming from the string. Is there any way, we can manually compile the jsx.

Remember that JSX isn't the same as HTML. When you write something like <Sections /> you are in fact writing React.createElement(Sections, null).
If you have "<Sections />" as a string and you want to resolve it to a call to React.createElement then you need to parse it as JSX. However, this happens at compile-time (not run-time) which would prevent you from using dynamic components.
If you want to work with a dynamic component, then your builder method must return a component class or a component instance.
function getDynamicComponent() {
return Sections;
}
function render() {
const Component = getDynamicComponent();
return <Component />;
}
// or
function getDynamicComponentInstance() {
return <Sections />;
}
function render() {
const component = getDynamicComponentInstance();
return component;
}
The only way to infer the correct component from "<Sections />" is to parse it manually and use eval to resolve the name to the appropriate variable. Parsing JSX is non-trivial and using eval is likely to open you up to a whole class of security vulnerabilities.
Unless your dynamic component name is coming from over the network, or from inside a separate worker, there's no reason why the function which returns your dynamic component can't be written like the example above.

Related

Separating the logic and the render() function from a component

I would like to be able to have a component whose rendering function is in another file in order to have a separation between the logic of my component and the rendering.
Naively, I tried to do just one file containing my component and which rendered a functional component of the same name to which I passed the necessary props so that everything was displayed correctly.
Something like that :
// MyComponent.render.jsx
export default MyComponentRender = (props) => {
return {
<View>
// render all components of my view
</View>
}
}
// MyComponent.js
class MyComponent extends Component {
// some logic
render() {
return (
<MyComponentRender
aLotOfProps=....
/>
)
}
}
But I soon found myself having to send, sometimes, a fairly large amount of props and +, I have for example textInputs that need to be focus() or blur() in reaction to some logic in my view but as a result, I couldn't control that just by sending props. It quickly became a mess!
I was wondering if there was a simple way to separate the logic of a component and its rendering function? Maybe there is a way to pass the context of my component to my rendering function/component so that it has direct access to all states and can also store references, etc.?
Thanks you,
Viktor

Functional components inside vs outside of React class

I am wondering what the effects of coupling / nesting a functional component inside a React class component without explicitly passing props to it via params and using this.props via the parent class are. I understand that having a functional component outside of the React class component is easier to test and read, but am curious to know what the exact difference between using this.props vs props via params are in terms of performance / renders.
For example:
class Foo extends React.Component {
bar = () => { return (<p>{this.props.baz}</p>) }
render() {
return (
<h1>Hello, {this.props.name}</h1>
{this.bar()}
)
}
}
Vs.
class Foo extends React.Component {
render() {
return (
<h1>Hello, {this.props.name}</h1>
<Bar baz={'foobar'}
)
}
}
function Bar(props) {
return <p>{props.baz}</p>
}
Both give the same result except when you care about code reusability.
If you care about reusing the Bar function then you better keep it outside the class so you can import it elsewhere.
Example:
If Bar renders a success or warning message. you'll want to keep the same design for all warning messages in the system.
Now if every component has its own warning message code, you'll not be able to edit the warning message design easily also you'll have to keep rewriting the same code over and over again.

React - should Higher Order Component be written as a function?

I'm learning React. It seems to me that HOC like the following example from React's official docs:
function withSubscription(WrappedComponent, selectData) {
// ...and returns another component...
return class extends React.Component {
constructor(props) {
super(props);
this.handleChange = this.handleChange.bind(this);
this.state = {
data: selectData(DataSource, props)
};
}
componentDidMount() {
// ... that takes care of the subscription...
DataSource.addChangeListener(this.handleChange);
}
componentWillUnmount() {
DataSource.removeChangeListener(this.handleChange);
}
handleChange() {
this.setState({
data: selectData(DataSource, this.props)
});
}
render() {
// ... and renders the wrapped component with the fresh data!
// Notice that we pass through any additional props
return <WrappedComponent data={this.state.data} {...this.props} />;
}
};
}
can be rewritten in this way:
class WithSubscription extends React.Component {
constructor({ component, selectData, ...props }) {
super(props);
this.handleChange = this.handleChange.bind(this);
this.state = {
data: selectData(DataSource, props)
};
}
componentDidMount() {
DataSource.addChangeListener(this.handleChange);
}
componentWillUnmount() {
DataSource.removeChangeListener(this.handleChange);
}
handleChange() {
this.setState({
data: selectData(DataSource, this.props)
});
}
render() {
return <component data={this.state.data} {...this.props} />;
}
}
Then use it like this:
<WithSubscription component={BlogPost} selectData={(DataSource) => DataSource.getComments()} />
Are they both HOC? When is one style preferred than the other?
I was struggling with HOC too at first. Another way of looking at this is at wrappers of components that you could use to isolate the functionality from one component.
For example, I have multiple HOC. I have many components that are only defined by props, and they are immutable once they are created.
Then I have a Loader HOC Component, which handles all the network connectivity and then just passes the props to whatever component is wrapping (This would be the component you pass to the HOC).
The loader does not really care which component it is rendering, it only needs to fetch data, and pass it to the wrapped component.
In your example, you can actually accomplish the same, however it will become much more complex once you need to chain multiple HOC.
For example I have this chain of HOCs:
PermissionsHOC -> LoaderHOC -> BorderLayoutHOC -> Component
First one can check your permissions, second one is loading the data, third one is giving a generic layout and the forth one is the actual component.
It is much easier to detect HOCs if you realize that some components would benefit from having a generic logic on the parent. You could do the same in your example, however you would need to modify the HOC every time you add a child component, to add the logic for that one. Not very effective. This way, you can add new components easily. I do have a Base component which every component extends, but I use it to handle the helper functions like analytics, logger, handling errors, etc.
What they call an "HOC" is basically a function (just a regular function, not React specific) that behaves like component factory. Meaning it outputs wrapped components that are the result of wrapping any inside-component of your choice. And your choice is specified with the "WrappedComponent" parameter. (Notice how their so-called "HOC" actually returns a class).
So I don't know why they called it an "HOC" tbh. It's just a function that spits out components. If anyone knows why I'd be interested in hearing the reason.
In essence their example is doing exactly what you're doing, but it's more flexible because WrappedComponent is being taken in as a parameter. So you can specify whatever you want. Your code, on the other hand, has your inside component hard coded into it.
To see the power of their example, let's say you have a file called insideComp.js containing:
import withSubscription from './withSubscription';
class InsideComp extends React.Component{
// define it
}
export default withSubscription(InsideComp);
And when you use insideComp in another file:
import myComp from './insideComp.js';
You're not actually importing insideComp, but rather the wrapped version that "withSubscription" had already spit out. Because remember your last line of insideComp.js is
export default withSubscription(InsideComp);
So your InsideComp was modified before it was exported
The second one is not a HOC.
They coin the word HOC from higher order functions. One example of a higher order function is a function that takes a function as an argument and returns another function.
Similarly, a HOC is a function that takes an component as argument and returns another component.
This does sound weird to me because a higher order component is not a react component; it is a function instead. I guess the reason they call it HOC is because:
A react component is a class, which is indeed a constructor function in JavaScript (except that functional components are simply functions). A HOC actually takes a function (a constructor function) and returns another function (another constructor function), so it is actually a higher order function if you think about it. Probably because it is in the react context and this is a pattern to transform components, they call it HOC.
As to the difference between the two styles you mentioned:
First one: you would use the first one to generate a class like MyComponnet = withSubscription(AnotherComponent, ...), and whenever you need it in a render call just write <MyComponent><MyComponent>
Second one: this is less common. Every time you need it in a render call, you would need to include the WithSubscription component as you mentioned in the description <WithSubscription component={BlogPost} selectData={(DataSource) => DataSource.getComments()} />

Is it possible to pass context into a component instantiated with ReactDOM.render?

TL;DR Given the following example code:
ReactDOM.render(<MyComponent prop1={someVar} />, someDomNode);
Is it possible to manually pass React context into the instance of MyComponent?
I know this sounds like a weird question given React's nature, but the use case is that I'm mixing React with Semantic UI (SUI) and this specific case is lazy-loading the contents of a SUI tooltip (the contents of the tooltip is a React component using the same code pattern as above) when the tooltip first displays. So it's not a React component being implicitly created by another React component, which seems to break context chain.
I'm wondering if I can manually keep the context chain going rather than having components that need to look for certain data in context AND props.
React version: 0.14.8
No. Before react 0.14 there was method React.withContext, but it was removed.
However you can do it by creating HoC component with context, it would be something like:
import React from 'react';
function createContextProvider(context){
class ContextProvider extends React.Component {
getChildContext() {
return context;
}
render() {
return this.props.children;
}
}
ContextProvider.childContextTypes = {};
Object.keys(context).forEach(key => {
ContextProvider.childContextTypes[key] = React.PropTypes.any.isRequired;
});
return ContextProvider;
}
And use it as following:
const ContextProvider = createContextProvider(context);
ReactDOM.render(
<ContextProvider>
<MyComponent prop1={someVar} />
</ContextProvider>,
someDomNode
);
In React 15 and earlier you can use ReactDOM.unstable_renderSubtreeIntoContainer instead of ReactDOM.render. The first argument is the component who's context you want to propagate (generally this)
In React 16 and later there's the "Portal" API: https://reactjs.org/docs/portals.html

How to access child component functions via refs

The docs for React state that component functions can be accessed by a parent component via refs. See: https://facebook.github.io/react/tips/expose-component-functions.html
I am attempting to use this in my application but run into an "undefined is not a function" error when the child function is called. I'm wondering if this has anything to do with using the ES6 format for React classes because I don't see any other differences between my code and the docs.
I have a Dialog component that looks like the following pseudocode. The Dialog has a "Save" button that calls save(), which needs to call the save() function in the child Content component. The Content component collects information from child form fields and performs the save.
class MyDialog extends React.Component {
save() {
this.refs.content.save(); <-- save() is undefined
}
render() {
return (
<Dialog action={this.save.bind(this)}>
<Content ref="content"/>
</Dialog>);
}
}
class Content extends React.Component {
save() {
// Get values from child fields
// and save the content
}
}
I could instead pass a prop (saveOnNextUpdate) down to Content and then execute save whenever it is true, but I would rather figure out how to get the method detailed in the React doc above to work.
Any ideas on how to get the doc approach to work or access the child component function in a different way?
Redux connect accepts an option parametre as the forth parameter. In this option parameter you can set the flag withRef to true. Then you can access functions to refs by using getWrappedInstance(). Like this:
class MyDialog extends React.Component {
save() {
this.refs.content.getWrappedInstance().save();
}
render() {
return (
<Dialog action={this.save.bind(this)}>
<Content ref="content"/>
</Dialog>);
}
}
class Content extends React.Component {
save() { ... }
}
function mapStateToProps(state) { ... }
module.exports = connect(mapStateToProps, null, null, { withRef: true })(Content);
Read more about it here: https://github.com/reactjs/react-redux/blob/master/docs/api.md#connectmapstatetoprops-mapdispatchtoprops-mergeprops-options
Worth reading this article about use of refs and consider if there's better approaches: https://facebook.github.io/react/docs/refs-and-the-dom.html#dont-overuse-refs
An alternative way to do this would be to use some other prop name (other than ref). I've found that this also works well if you're using a library like styled-components or emotion For example in a connected MyComponent:
<MyComponent
...
innerRef={(node) => { this.myRef = node; }}
/>
As it turns out, m90 was right -- this was a different issue entirely. I'm posting the solution in case someone runs into the same problem in the future.
My application is built with Redux, and the problem stems from using the react-redux connect function to connect a component to the store/global state. For some reason, exporting a component and connecting it to the store makes it impossible to access the functions inside of it. In order to get around this, I had to remove all use of global state from Content so that I could export it as a "dumb" component.
To be more clear, Content.js looked like this:
var connect = require('react-redux').connect;
class Content extends React.Component {
save() {
// Get values from child fields
// and save the content
// Use of this.props.stateObject
}
}
function mapStateToProps(state) {
const {
stateObject
} = state;
return {
stateObject
};
}
module.exports = connect(mapStateToProps)(Content);
Removing the use of global state (and therefore the use of connect and mapStateToProps allowed me to export the component using:
module.exports = Content;
Accessing this.refs.content.save() magically worked after doing this.

Categories