How I can render react components without jsx format? - javascript

I try to make my "smart" popup component, which can open inside itself some components, but my realization isn't good, because it doesn't work.
I use redux approach for creating popup and action of opening my popup is able to get name of any component for rendering before popup will be open;
But I've some problem, after getting parameter, in our case it's nameOfComponent, I need to choose and render component with name nameOfComponent.
And my question now, how do It can render component from array?
// He's my components
import Login from '../Login/login.js';
import Logout from '../Logout/logout.js';
const popupContent = {
Login : Login,
logout: Logout
};
// My component
class Popup extends Component {
componentDidUpdate () {
// for example
const nameOfComponent = "Login";
this.body = this.setBodyPopup(nameOfComponent);
return true;
}
setBodyPopup(property){
return popupContent[property];
}
render() {
// I want to render some element from popupContent here
<div>
// <this.body /> // it's jsx format
{this.body}
</div>
}
}

I added working example here JSfiddle ReactJS
You dont have to use JSX. If you do, right way to do this is to use factory. You can also render regular HTML in the render method, as well as to use vanilla javascript in your code using curly braces.
Also to get I would recommend mapping and iterating through all your items in array and render them one by one in the render method
see example below:
var Login = React.createClass({
render: function() {
return <div>{this.props.name}, logged in</div>;
}
});
// React with JSX
ReactDOM.render(<Login name="John" />,
document.getElementById('containerJSX'));
// React without JSX
var Login = React.createFactory(Login);
ReactDOM.render(Login({ name: 'Tim' }),
document.getElementById('containerNoJSX'));

As commentators suggest, you might want to specify this.body either in constructor or within the render method itself.
However, if I understand your intention correctly, you could just use this.props.children instead.
E.g.
<Popup><MyInnerComponent></Popup>
and in Popup render method
render() {
<div>
{this.props.children}
</div>
}

React actually allows you to use variables with JSX syntax to instantiate components. You should actually be able to call <this.body /> and have it work; however yours will not because you do not define this.body until the componentDidUpdate method, which means it will be undefined for the first render and break everything. I would suggest using local component state for this instead of this.body and making sure it is defined from the start.
At the very least, instantiate this.body in a constructor to some value:
constructor(props) {
super(props);
this.body = 'Login';
}

You can use <this.body /> to render the component, as long as this.body has an actual value. Perhaps you just need:
render() {
return <div>
{this.body ? <this.body /> : null}
</div>
}
With the example you gave, though, you can just put the contents of your componentDidMount in the constructor instead, because the constructor is invoked before the first render pass.

I think you are looking at something like dangerouslySetInnerHtml.
<div dangerouslySetInnerHTML={this.body} />

Related

Rendering a component in JSX vs via function

When using React, what is the difference (and when should each method be applied) when rendering a component?
Does this impact the component lifecycle in any way? Or impact how hooks are run in the component?
Method 1:
class App extends React.Component {
...
function getComponent() {
return <Component />
}
render() {
return this.getComponent()
}
}
Method 2:
class App extends React.Component {
...
render() {
return <Component />
}
}
(Note: The OP has now changed the question, it used to have return {this.getComponent()} in Method 1.)
render in Method 1 is incorrect (well, it was before the edit), it should be:
render() {
return this.getComponent() // No {} wrapper
}
You need the {} within a JSX context, but you're not in a JSX context there. For instance, if you wanted to wrap what this.getComponent returned in a div, you'd use the JSX expression to define the div's children within the JSX defining the div:
render() {
return <div>{this.getComponent()}</div>
}
With the {} sorted out, whether you use Method 1 or Method 2 is up to you. If you have substantial parts of the render that you want to move into their own functions, that's fine. For instance:
render() {
return (
<div>
{this.getHeader()}
{this.getBody()}
{this.getFooter()}
</div>
);
}
...although I think I'd probably argue at that point that without a good counter-argument, the header, body, and footer should probably be components (perhaps function components). But the occasional helper function call like that is fine.
Does this impact the component lifecycle in anyway?
No. It's just a function call within render.
There is no real difference between both. I'd personally use only one render() method as much as possible, then when the method gets too big, extract parts of it into their own method.
I have found this great article by Kent C. Dodds. An extract of the article is:
React doesn't know the difference between us calling a function in our JSX and inlining it. So it cannot associate anything to the Counter function, because it's not being rendered like a component.
This is why you need to use JSX (or React.createElement) when rendering components rather than simply calling the function. That way, any hooks that are used can be registered with the instance of the component that React creates.
With this in mind, it sounds like it's better to use JSX when rendering a component that uses hooks.

Storing methods needed in all components

I have a universal app I'm developing for learning purposes. I'm managing the state of my app with Redux, so all my data will be available there. But I want to create some methods that I'm going to use in all my components. The problem is: where should I store this methods?
Adding them to a parent component and passing the methods as props doesn't seem very useful, because this is one of the things that Redux tries to solve. And I'm pretty sure that Redux is not a place for storing methods.
I know I can create a class in a file somewhere, export it, add some methods to it, and when I want to use one method in a component I can call this file, create an instance of the class and call the needed method; but this doesn't look very react to me…
Is there a right way to create methods available for all components?
I've had some success sharing functions between components using an approach similar to the following. I'm not sure this approach will solve your specific use case with regards to cookies, however.
These functions can be stored anywhere and imported wherever required. They accept a component as their first argument, then return a function that operates on the component passed in.
Indicative, untested code follows.
// An event handler than can be shared between multiple components
const handleChange = component => event => component.setState({ value: event.target.value });
class ComponentOne extends PureComponent {
state = {};
render() {
return (
<div>
{this.state.value}
<input onChange={handleChange(this)} />
</div>
);
}
}
class ComponentTwo extends PureComponent {
state = {};
render() {
return (
<div>
{this.state.value}
<input onChange={handleChange(this)} />
</div>
);
}
}

How to manipulate HTML data that comes from the server using ReactJS

So I have this data that comes from the server:
const userInfo = getUserInfo(); //Returns: <span class="info">His name is Sam</span><span class="info">He is 20 years old</span><span class="info">He is from Spain</span><span class="info">He is fluent in English</span>
Then, there are two react components. The first one, ListInfo, shows all of the user info and if the second component, ShowMore, is added to the page, the ListInfo should have to show only the first two pieces of information.
class ListInfo extends React.Component {
render() {
return (
const info = this.props.info;
<div className="ListInfo">
{info}
<ShowMore items={info} />
</div>
);
}
}
class ShowMore extends React.Component {
constructor(props) {
super(props);
this.state = {
isDisplayingAll: true
};
this.handleDisplaying = this.handleDisplaying.bind(this);
}
componentDidMount() {
this.setState({
isDisplayingAll: false
});
}
handleDisplaying(e) {
}
render() {
return (
<button onClick={this.handleDisplaying}>
{this.state.isDisplayingAll ? 'Less' : 'More'}
</button>
);
}
}
ReactDOM.render(
<ListInfo info={userInfo} />,
document.getElementById('root')
);
So here comes the questions:
Firstly, react documents say that you should add a key property if you're rendering items of lists, and the info that comes from the server is a list. So how could I add a key to them? I mean, do I have to write some code to add a key to each item?
Secondly, I should not change the props that a component gets, so how should I change the style of the DOM elements (the last two ones)?
Thirdly, would elements having class instead of className make a problem in rendering?
I think your best bet would be to set up your backend to serve the data as JSON. Then you can write out the JSX to avoid the problems with syntax differences.
If you are absolutely constrained to HTML for some reason, I've had success using react-magic in the past to translate the HTML into JSX. I think I have a webpack loader lying around here somewhere if you want it.
I believe you have a disconnect between JSX, what React uses, and actual HTML. Even though React looks to be using HTML inside of JS, it's actually using some compiler tricks to turn the HTML into JS statements. This explains your first question and third question.
Take a look at this page for what is actually happening under the hood of React.
https://reactjs.org/docs/react-without-jsx.html
There is a way to use the HTML returned back from the server directly in a component. I would read over the Docs here to see how to do it and what are the pros and cons of doing so.
https://reactjs.org/docs/dom-elements.html#dangerouslysetinnerhtml
Normally components expose a style prop that allows you to override the default style. I would look into the docs to see if the components you are wanting to style have a style prop.

react how to call state variable from another class?

Search.js
class Search extends Component {
constructor() {
super();
this.state = {
selectedPictures: []
}
}
static getSelectedPictures = () => {
return this.state.selectedPictures;
}
render() {
return (
<div>
...
</div>
);
}
}
export default Search;
Other.js
import Search from './Search';
class Other extends Component {
constructor() {
super();
this.state = {
}
}
render() {
console.log(Search.getSelectedPictures); --> Uncaught null
return (
<div>
...
</div>
);
}
}
export default Other;
How to call Search.state.selectedPictures inside Other.js?
I already try to use static method to return this.state.selectedPictures and call in Other.js, but cannot access.
Any way can import or transfer the var? Both js files are separate files
Thank you.
What you're trying to do isn't really possible in React for a couple of reasons. First of all, you're trying to call methods and access properties on a class, not on an object. You would, in normal (modern) JS, be required to instantiate the class with the new keyword. For example, search = new Search(); search.getSelectedPictures() - this, however, isn't really how React works, and because your classes are actually components, you have to use the <Search/> component syntax in your render function.
As for getting access to the state in Search, you'd need to pass that state from Search to Other.
One way would be to pass the state into the props directly, so in search.js:
render() {
<Other selectedPictures={this.state.selectedPictures} />
}
Then in other.js:
render() {
this.props.selectedPicture.forEach((pic) => <img src={pic} />);
}
Alternatively, you could have a more umbrella parent component, and keep the state in there. Then pass that state to both components simultaneously, if the ones you list are not meant to have a parent-child relationship.
There are also, albeit slightly more complex, ways of doing what you wish but with Search as a child of Other, but without knowing what those two components actually are, it's hard to really tell.
Use flux architecture . The simple implementation is
alt flux
Just create an Action and a Store . When you select images just put them in the Store using Action then get them as props using <AltContainer />

React: How to check the type of a child in the parent's render function?

I know that during render I can get the child through refs and, for example, call a function on the child (which I can add to the child for this purpose) to determine the type of the child.
<Child ref={(child) => {this._childType = child.myFunctionToGetTheType();}} />
But in this example the function isn't actually called until the Child is mounted, so after the render of the Parent has finished executing.
I have a parent component that receives its children through props. Because of React limitations I need to treat a specific child in a special way BEFORE the render of the parent has finished executing (i.e. return something else from the parent's render function for that specific child).
Is it possible to determine the type of the child before returning from the parent's render function (i.e. without using refs)?
I've had the same issue, where I was relying on child.type.name to determine the type of component. While this works fine for me, the issue is that older browsers somehow do not support that so I had to find another way. I was using Stateless Functional Components and did not want to switch away, so ended up exploiting props
const MySFC = () => {
//...
return (
<div className="MySFC"></div>
);
};
MySFC.propTypes = {
type: PropTypes.string
};
MySFC.defaultProps = {
type: "MySFC"
}
export default MySFC;
then instead of using child.type.name === 'MySFC' I used child.props.type === 'MySFC'
not ideal, but works
I have added a static function to the class that extends React.Element and it seems that I am able to access it through child.type.theStaticFunction. That probably still isn't using the React API correctly but at least it works after the code has been minified (child.type.name didn't work because the minifier was replacing class names with shorter versions).
export default class MyType extends React.Component {
static isMyType() {
return true;
}
}
then when processing the children in render
static _isChildOfMyType(child) {
const isMyType = child.type && child.type.isMyType && elem.type.isMyType();
return !!isMyType;
}

Categories

Resources