React.js How to render component inside component? - javascript

I am stuck. I have several seperate components on seperate files. If I render them in main.jsx like following:
ReactDOM.render(<LandingPageBox/>, document.getElementById("page-landing"));
ReactDOM.render(<TopPlayerBox topPlayersData={topPlayersData}/>, document.getElementById("wrapper profile-data-wrapper"));
ReactDOM.render(<RecentGamesBox recentGamesData={recentGamesData}/>, document.getElementById("history wrapper"));
Everything works fine, but I wonder if it is a good practice? Maybe it is possible to do something like there would be only one ReactDom.render like:
ReactDOM.render(<LandingPageBox recentGamesData={recentGamesData} topPlayersData={topPlayersData}/>, document.getElementById("page-landing"));
I tried different kinds of variatons of LandingPageBox to somehow include those other two components, but had no luck. They sometimes rendered outside the page and so on. I thought it should look something like this:
import React from 'react';
import RecentGames from '../RecentGames/RecentGames.jsx';
import TopPlayers from '../TopPlayers/TopPlayers.jsx';
import PageTop from './PageTop.jsx';
import PageBottom from './PageBottom.jsx';
class LandingPageBox extends React.Component {
render() {
return (
<body className="page-landing">
<PageTop>
<TopPlayers topPlayersData={this.props.topPlayersData} />
</PageTop>
<PageBottom>
<RecentGames recentGamesData= {this.props.recentGamesData}/>
</PageBottom>
</body>
);
}
}
export default LandingPageBox;
But this code only renders PageTop and PageBottom, without player or game components.
So my question would be, how to set up LandingPageBox file so that TopPlayers component would render inside PageTop component and RecentGames component would render inside PageBottom component? Thank you.

In your example
return (
<body className="page-landing">
<PageTop>
<TopPlayers topPlayersData={this.props.topPlayersData} />
</PageTop>
<PageBottom>
<RecentGames recentGamesData= {this.props.recentGamesData}/>
</PageBottom>
</body>
);
React will only render the top-level custom components PageTop and PageBottom, as you already found out. The other components (TopPlayers and RecentGames) are nested within those components. What does that mean? React does not just display those nested components because it would not know how to do this. Instead, all rendering must be done by the outer components PageTop and PageBottom. React just passes the nested components to them (PageTop gets TopPlayers, PageBottom gets RecentGames) in this.props.children. Now it is up to the outer components what to do with these nested components. In your example, you would modify the PageTop and PageBottom components to use {this.props.children} to display their nested components in a suitable way.

You are right. You can use as many nested components as you want. It's one of the main concepts in react.
You can access them in this.props.children.
Do it like this:
var Parent = React.createClass({
render: function() {
return <div>{this.props.children}</div>;
}
});
ReactDOM.render(
<Parent>
<Child/>
<Child/>
</Parent>,
node
);
Read more here - https://facebook.github.io/react/docs/multiple-components.html
And here - http://buildwithreact.com/article/component-children

Here Car component is inside the another component i.e Garage components.
When Garage component in rendering Car component is also renders.
Same concept as like one function inside another function.
class Car extends React.Component {
render() {
return <h2>I am a Car!</h2>;
}
}
class Garage extends React.Component {
render() {
return (
<div>
<h1>Who lives in my Garage?</h1>
<Car />
</div>
);
}
}
ReactDOM.render(<Garage />, document.getElementById('root'));

Related

Splitting ReactJS onto multiple assemblies

Ive got a modular .NET application, which loads controllers, views and components from assemblies as plugins.
Going to learn React (totally new to it) - and got a question. Does React support splitting its components into multiple assemblies and loading them at runtime?
Yes, it does.
I suggest you to read React official documentation.
Almost every React component will produce some HTML markup for browser to show. The general idea of component splitting is to split HTML markup between several components like so
// App.js
class App extends React.Component {
render () {
return <div>
My first component
<Component1/>
</div>
}
}
// Component1.js
export default class Component1 extends React.Component {
render () {
return <div>
This is internals of component
</div>
}
}

Pass React Props to a Separate JS File

I'm trying to pass props for width from a parent component to a child JS file, but cannot seem to get the props value in the child JS file. The parent is the following:
import React from 'react';
import Child from './Child';
export default class Home extends React.Component {
state = {
width: 1000
}
render(){
return(
<div>
<Child width={this.width} />
</div>
);
}
}
The separate child JS file is the following:
import React from 'react';
const svgWidth = 650, // Load prop here
svgHeight = 340;
What I've tried is the following but is not working for me:
import React from 'react';
const Child = (props) => {
console.log({props.width}); // Getting an error that ',' is expected
return {props.width};
}
Can someone please help me with passing the width value from ?
Change to the following, as you should access state through this.state, like so:
<Child width={this.state.width} />
Either use the prop drilling, hence pass the values from parent to child as a prop.
But exact answer to your question will be :
create a blank object in separate js file and export it and then in componentDidMount populate that object with the props which you want to save. Next time when ever you will use that object anywhere in normal js file you will get the props.
If you intend to pass props to a child component, then I would start with the following:
import React from 'react';
import Child from './Child';
export default class Home extends React.Component {
constructor(props) { // don't forget to add a constructor
super(props); // also required
this.state = {
width: 1000
}
}
render(){
// to pass state use {this.state}
return(
<div>
<Child width={this.state.width} />
</div>
);
}
}
However, if that is not the case and instead you want to export state to a separate js file (that may not even be a React component), then you may have to look at export syntax. I am struggling with a similar problem right now and I already tried what Vikash Kumar suggested without success. This is explained on this question but I was not successful with that approach either: export function inside react component or access state in same file outside of component

Meteorjs + React, how to render several elements in Meteor.startup

I am trying to declare two different React elements that I would like to render. The both elements are separated elements such as displayed elements (App.jsx) and the customized account system (Login.jsx). But in my test I have the same code in the both jsx file to ensure that the issue is not related to a specific part of them.
I have also created an /imports/startup/client/index.js file (called in the /client/main.js file):
import React from 'react';
import { Meteor } from 'meteor/meteor';
import { render } from 'react-dom';
import './accounts-config.js';
import App from '/imports/ui/App.jsx';
import Login from '/imports/ui/Login.jsx';
Meteor.startup(() => {
render(<App />, document.getElementById('app'));
render(<Login />, document.getElementById('login'));
})
and the /client/main.html contains the related div tags:
...
<div id="app"></div>
<div id="login"></div>
...
The issue is that the second render is never displayed (here, the div login) and I observe that only the first render is interpreted.
All the examples that I've found only deals with a single react element. So I wonder how to use several separated react elements like it is in my html file ?
I am newbie in the meteorjs and react world , so maybe I didn't get the right philosophy...
You can make use of React 16 new feature that is portal.
For how to use ReactDOM.createPortal please refer to following link:
How to use ReactDOM.createPortal() in React 16?
I have solved my issue using only one render in the Meteor.startup(() (in my index.js).
The React doc specifies that only one render can be declared in the Meteor.startup(() (in my index.js).
https://reactjs.org/docs/components-and-props.html
My code is the following:
in my index.js
Meteor.startup(() => {
render(<App />, document.getElementById('app'));
})
The trick is that this Super component (App.jsx) has to be used to call all the other components. In my example by calling the Login component:
render() {
return (
<div className="container">
<Login />
</div>
)
}
I believe because the render() statement has an implicit return statement as well, so since it can only execute and return one, the next render statement isn't executed.

React Components - Where to store HTML Templates

Complete newbie to React and trying to find out how to load the HTML for components rather than inserting it directly in the render method. For example
import React, {Component} from 'react';
export default class Login extends Component {
render() {
return (
<!-- how can I provide a link to the HTML template for here? -->
);
}
}
React does not have HTML. The JSX that you write in the render method is actually compiled into JavaScript. At the core, React components are all JavaScript. The styles are also inline. Componentisation is neat in React because HTML, CSS, JavaScript (interactions) are all in one place, as JavaScript.
To insert raw HTML, React has an attribute dangerouslySetInnerHTML.
<div dangerouslySetInnerHTML={createMarkup()} />
If you want some type of organization, you can use variables to set the html and then assign that to the render functionalty, but React does not use html templates
var hello = React.createClass({
render: yourVariable
});
I think you might be confused about how JSX works.Just in case, I want to clarify that JSX is what they call "syntactic sugar", that turns React methods such as React.createElement into that XML like syntax. For instance:
var Nav;
// Input (JSX):
var app = <Nav color="blue" />;
// Output (JS):
var app = React.createElement(Nav, {color:"blue"});
(from the React docs)
So, to the best of my knowledge, the JSX syntax actually belongs in the render method. If what you are really looking for is the best way to separate and reuse purely presentational code, you should read on separating your app into Container and Presentational components
https://medium.com/#learnreact/container-components-c0e67432e005#.dzjqc8yrn
https://medium.com/#dan_abramov/smart-and-dumb-components-7ca2f9a7c7d0#.mn9nf6lz6
Stateless/Presentational/Dumb Components are just functions that return JSX. So you could have your Template component:
import React from 'react';
//you need to import React to use JSX, as it will be expanded into React.createElement calls...
function Template(props){
return (
//...your template here...
);
}
And then your class
import React, {Component} from 'react';
export default class Login extends Component {
render() {
return (<Template {...props}/>);
}
}
}
Makes sense?

Testing functional components with renderIntoDocument

I am learning to test React stateless components using the ReactTestUtils library. This is my simple component:
import React from 'react';
const Greeter = ({name,place}) => (
<h1>Hello,{name}. Welcome to the {place}.</h1>
);
export default Greeter;
This is my test spec, to get the renderIntoDocument working, I wrapped my Greeter component in a div as suggested here:
import {expect} from 'chai';
import React from 'react';
import ReactTestUtils from 'react-addons-test-utils';
import Greeter from '../Greeter';
describe('Greeter Components',() => {
it('renders correctly',() => {
var component = ReactTestUtils.renderIntoDocument(<div>
<Greeter name="Vamsi" place="Hotel California"/>
</div>);
var hasH1 = ReactTestUtils.findRenderedDOMComponentWithTag(component,'h1');
expect(hasH1).to.be.ok;
});
});
I get the error
findAllInRenderedTree(...): instance must be a composite component.
I am providing my code as jsbin here.
Since function components don't have an instance associated with them, you can't use them directly with render or renderIntoDocument. Attempting to wrap the function component is a good idea, unfortunately using a div doesn't work for a similar reason. DOM components also don't return a component instance, instead they return the underlying DOM node.
Which is all to say that you can't use the test utils function or native components as the "root" component you are rendering. Instead you will want to wrap your function components in a wrapper component that uses createClass or extends React.Component.
class Wrapper extends React.Component {
render() {
return this.props.children
}
}
let component = renderIntoDocument(<Wrapper><Greeter /></wrapper>
Gotcha's like this may be reason enough to make use of a third-party testing library like the popular enzyme, or my own take: teaspoon. Both abstract over issues like this by seamlessly wrapping and unwrapping function components for you, so you don't need to worry about what type of component you are trying to render.
Wrapping functional components in a <div> works for me. You just have to search for the component you want to test a little differently, i.e.
const props = { p1: "1" }
test('Foo renders correctly classed div', () => {
const cpt = TestUtils.renderIntoDocument(<div><Foo {...props} /></div>);
const myNode = ReactDOM.findDOMNode(cpt.childNodes[0]);
expect(myNode.className).toBe('my-class');
});
notice that you can target myNode for testing using cpt.childNodes[0]
In order to improve #monastic-panic's answer, my two cents:
You don't have to create a class for that. Do it dynamically:
import createReactClass from 'create-react-class';
// need to be a class component
const Clazz = createReactClass({
render: () => {
return <YourFunctionalComponentName {...props} />;
},
});
ReactTestUtils.renderIntoDocument(<Clazz />);

Categories