I'm trying to follow along with the reactjs tic tac toe tutorial, but when I try to render the pages and I have this code
import React from 'react'
import ReactDOM from 'react-dom'
import Game from '../components/Game'
document.addEventListener('DOMContentLoaded', () => {
ReactDOM.render(
console.log("render is working"),
<Game />,
document.getElementById('root'),
);
})
and the Game class looks like
import React from 'react'
import ReactDOM from 'react-dom'
import Board from './Board'
class Game extends React.Component {
render() {
console.log("Hooray, the game is working")
return (
<div className="game">
<div className="game-board">
<Board />
</div>
<div className="game-info">
<div>{/* status */}</div>
<ol>{/* TODO */}</ol>
</div>
</div>
);
}
}
export default Game
The 'render is working prints to the console but the console log that says "Hooray, the game is working" doesn't show up, so it seems like the
Game class isn't getting rendered for some reason. I'm using ruby on rails with the built in webpacker to load all the javascripts
Cause calling console.log evaluates to undefined you are basically doing:
ReactDOM.render(
undefined, // <- react component
<Game />, // <- target
document.getElementById('root'), // < - useless
);
I'm surprised that ReactDOM.render is not throwing an error although you are passing completely useless arguments to it.
ReactDOM.render() takes 2 arguments: component, and mounting DOM element. You are passing a console.log for the first argument.
For one, why do you have your ReactDom.render(...) wrapped in that event listener?
Two, why are you passing the ReactDom.render(...) a console.log()? It should only take two arguments: a component, and the element it should be appended to. Try removing the console.log() and if that still doesn't work, try removing the event listener that wraps your ReactDoom.render(...).
You need to remove the console log from the ReactDOM render call.
If I need to render in a component, I can do it as such.
<div>
.....
{console.log('Inline console in render method')}
</div>
Your render should be as follows:
ReactDOM.render(<Game />, document.getElementById('root);
Assuming your child component is passed as 'export default Game' and your Id of your HTML base file is 'root'.
Render only takes two arguments. The first being the component being passed in and the second is the target in which it should place itself. You should only need to do this step at your 'index.js' file. Nowhere else.
Related
I came up with a mind-boggling situation, which did not (at least yet) cause any problems, but I couldn't find anything by googling.
A theoretical (and unrealistic but illustrative) example of two React Components:
// parent.js
import Child from "./path-to-child";
export function Parent(props) {
return(
<Child content="some content" />
);
}
// child.js
import withContext from "./path-to-context";
function Child(props) {
return(
<p>
{props.content}
</p>
);
}
export default withContext(Child);
So the Parent is passing content as a prop to Child. If the context provided by withContext HOC also happened to have a property with name content, what would happen? Is there an order of precedence or is content just the latest value which happens to overwrite the older one or perhaps something else?
I am learning the react and I made a component and inside that I have a on click function and I have a console statement inside that, can anyone explain why it is displaying two times on the render
import React from 'react';
class App extends React.Component {
render() {
return (
<>
<button onClick={console.log("hello")}>Change name</button>
<h1>hello my name is kushal</h1>
</>
) } }
export default App;
below is the screenshot of the running app for reference
OK one hello is print because the function onclick function invoke immidetly but why the second one prints
Your code is also calling the function when the button is rendered. The correct way is to use an arrow function:
import React from 'react'; class App extends React.Component {
render() {
return (
<>
<button onClick={() => console.log("hello")}>Change name</button>
<h1>hello my name is kushal</h1>
</>
)
}
}
export default App;
EDIT: The other console.log() is triggered by something unrelated to the code you shared in your question. As you mentioned in the answer below it was triggered by the strictMode you used in your app wrapper:
<React.StrictMode>
<App />
</React.StrictMode>
Ok i found why it prints two times
one hello is printing immediately because of the simple function insted of the es6 function , and the other one is because of the React.strictMode in the index.js file , i have removed the <React.StrictMode> from index.js and now it is printing only one time,
<React.StrictMode>
<App />
</React.StrictMode>
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.
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'));
I am trying to build a component which,
Takes children and
Renders the children in the DOM and also,
Shows the children DOM in a pre for documentation sake
One solution is to pass the JSX as a separate prop as well. This makes it repetitive since I am already able to access it through this.props.children. Ideally, I just need to somehow convert the children prop as a string so that I can render it in a pre to show that "this code produces this result".
This is what I have so far
class DocumentationSection extends React.Component{
render(){
return <div className="section">
<h1 className="section__title">{heading || ""}</h1>
<div className="section__body"> {this.props.children}</div>
<pre className="section__src">
//Change this to produce a JSX string from the elements
{this.props.children}
</pre>
</div>;
}
}
How can I get the a jsx string in the format '<Div className='myDiv'>...</Div> when I render DocumentationSection as
<DocumentationSection heading='Heading 1'>
<Div className='myDiv'>...</Div>
</DocumentationSection>
Thanks.
Edit:
I tried toString, it dint work, gave [object Object]
If you want the HTML representation of a React element you can use #renderToString or #renderToStaticMarkup.
ReactDomServer.renderToString(<div>p</div>);
ReactDomServer.renderToStaticMarkup(<div>p</div>);
will produce
<div data-reactid=".1" data-react-checksum="-1666119235">p</div>
and
<div>p</div>
respectively. You will however not be able to render the parent as a string from within itself. If you need the parent too then from where you render the parent pass a renderToString version of it as props to itself.
React.renderToString is depreciated as of React v0.14.0, it's recommended to use ReactDOMServer.renderToString instead.
e.g
import ReactDOMServer from 'react-dom/server'
...
ReactDOMServer.renderToString(YourJSXElement())
You can use react-element-to-jsx-string:
import React from 'react';
import reactElementToJSXString from 'react-element-to-jsx-string';
console.log(reactElementToJSXString(<div a="1" b="2">Hello, world!</div>));
// <div
// a="1"
// b="2"
// >
// Hello, world!
// </div>
You can also use the pretty-format package, which is part of Jest, and used by Jest to show the diffs in JSX assertions.
import React from "react";
import prettyFormat from "pretty-format";
import renderer from 'react-test-renderer';
const { ReactTestComponent } = prettyFormat.plugins;
function App() {
return (
<div className="App">
<h1>Hello CodeSandbox</h1>
<h2>Start editing to see some magic happen!</h2>
</div>
);
}
console.log(
prettyFormat(renderer.create(<App />), {
plugins: [ReactTestComponent],
printFunctionName: true,
})
);
This will output something like:
<div
className="App"
>
<h1>
Hello CodeSandbox
</h1>
<h2>
Start editing to see some magic happen!
</h2>
</div>
You can try it by yourself in this CodeSandbox: https://codesandbox.io/s/xvxlw370xp