I've been trying to get into React and therefore read the official guides, however, I'm not sure how to put components into their own files to reuse them across files.
I've made a very basic React Component which holds an input tag and some configuration with it. I would like to make this input tag a standalone component in its own file. How do I achieve this?
I use Webpack with this configuration:
var path = require('path');
var webpack = require('webpack');
module.exports = {
devtool: 'eval',
entry: [
'webpack-dev-server/client?http://localhost:3000',
'webpack/hot/only-dev-server',
'./src/index'
],
output: {
path: path.join(__dirname, 'dist'),
filename: 'bundle.js',
publicPath: '/static/'
},
plugins: [
new webpack.HotModuleReplacementPlugin()
],
module: {
loaders: [{
test: /\.js$/,
loaders: ['react-hot', 'babel'],
include: path.join(__dirname, 'src')
}]
}
};
This is the React code:
import React, { Component } from 'react';
export default React.createClass({
getInitialState: function() {
return {text: ''};
},
handleChange: function(e) {
this.setState({text: e.target.value})
},
render() {
return (
<div>
<h1>What's your name?</h1>
<input
type="text"
value={this.state.text}
onChange={this.handleChange}
/>
<h2>Hallo, {this.state.text}</h2>
</div>
);
}
});
Edit: I forgot the index.js:
import React from 'react';
import { render } from 'react-dom';
import App from './Components/App';
render(<App />, document.getElementById('root'));
Thanks.
You will want to create an input component and pass your state and handle change function as props to the component.
Input Component :
import React, {Component} from 'react';
var Input = React.createClass({
handleChange: function(e) {
this.props.handleChange(e.target.value);
}
render() {
return (
<input
type="text"
value={this.props.text}
onChange={this.handleChange} />
)
}
});
export default Input;
Your current component (with the input component added in):
import React, { Component } from 'react';
import Input from './path_to_inputComponent';
export default React.createClass({
getInitialState: function() {
return {text: ''};
},
handleChange: function(text) {
this.setState({text: text})
},
render() {
return (
<div>
<h1>What's your name?</h1>
<Input text={this.state.text} handleChange={this.handleChange} />
<h2>Hallo, {this.state.text}</h2>
</div>
);
}
});
So what will happen is, this.state.text will be passed as the text prop to Input which will set the value of the input. This will allow the input component to be used in multiple places and have a different value in each place that it is used. Also, when the onChange event is fired from the input, it will call the function that handleChange function that is passed to it as a prop. Therefore, it will call the function in the parent component and the state will be updated in the parent component.
Related
I am trying to make a SSR react app, but not able to pass props from express to the component.
What mistake am i doing?
server.js
import AppPage2 from './src/project02/LandingPage';
......
......
server.get('/project2',async (req,res)=>{
const context = {data:'test'}
const sheet = new ServerStyleSheet();
const content = ReactDOMServer.renderToString(sheet.collectStyles(
<StaticRouter location={req.url} context={context}>
<AppPage2 state={{"foo":"baar"}}/>
</StaticRouter>)
);
const styles = sheet.getStyleTags();
let html = appShell( 'Project 2', content,' project2.bundle.js',styles)
res.status(200).send(html);
res.end()
})
AppPage2(./src/project02/LandingPage)
import React from 'react';
import {Wrapper,Title} from './styleComponent/testStylePage'
.......
.......
class AppPage extends React.Component {
componentDidMount() {
console.log("{{API}}",this,this.props, this.props.staticContext)
}
render(){
return(
<Wrapper>
<Title>This is project 01 </Title>
</Wrapper>
)
}
}
export default AppPage;
index.js
import React from 'react';
import ReactDOM from 'react-dom';
import AppPage from './project02/LandingPage'
ReactDOM.hydrate(
<AppPage></AppPage>,
document.querySelector('#root')
);
webpack.client.conf
const path = require('path');
const glob = require("glob");
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
const entry = glob.sync("src/*.js")
.reduce((x, y) => Object.assign(x,
{
[y.replace('src/','').replace('.js','')]: `./${y}`,
}
), {});
module.exports = {
target: 'node',
mode: 'development',//development,production
entry: entry,
output: {
filename:'[name].bundle.js',
path: path.resolve(__dirname,'build/public/'),
publicPath: '/build/'
},
module: {
rules: [
{
test: /\.js$/,
exclude: /(node_modules)/,
use: {
loader: 'babel-loader'
},
},
]
},
plugins: [
// new BundleAnalyzerPlugin()
]
}
I am not able to log console.log("{{API}}",this,this.props, this.props.staticContext) from AppPage2(./src/project02/LandingPage) this page i am sending data from server.js(express)
Your props already passed to your component on Page2, but you're longing it using a function that will never been called,
componentDidMount() is invoked immediately after a component is mounted (inserted into the DOM tree).
in your case, you are not mounting any thing to the DOM, because react will only render your component to html and will not wait for your component to Mount, practically there is no DOM in your NodeJs server, and you're only rendering the component and return it as string, not inserting it to the DOM.
Your props are already there and you can console log them in your class constructor, and in your render method:
class AppPage extends React.Component {
constructor (props){
super(props)
console.log("{{API}}",this,this.props, this.props.staticContext)
}
render(){
//or console log it here
console.log("{{API}}",this,this.props, this.props.staticContext)
return(
<Wrapper>
<Title>This is project 01 </Title>
</Wrapper>
)
}
}
in this state your compoenent will mount and not did mount you can also console log your props using UNSAFE_componentWillMount but as it's name said it's unsafe
ReactJS.org
You can also create your own functions and it will works:
myFunction () {
console.log(this.props.state)
}
myFunction();
I am using a basic codebase in React that uses Webpack to compile ES6 and JSX to be backwards compatible.
I created a component using ES6 syntax and I want to display a props value into the component but I get an error in the console that says:
Uncaught ReferenceError: myCheese is not defined
at Module../src/index.js (index.js:8)
at webpack_require (bootstrap:18)
at startup:3
at startup:5
App.js
import React from "react";
import { hot } from "react-hot-loader";
class App extends React.Component {
render() {
return (
<div>
<p>Another paragraph</p>
<p>{this.props.msg}</p>
<p>
<strong>Cheese name: </strong> {this.props.cheese.name}
</p>
</div>
);
}
}
var myCheese = {
name: "Camembert",
smellFactor: "Extreme pong",
price: "3:50",
};
export default hot(module)(App);
index.js
import React from "react";
import ReactDOM from "react-dom";
import App from "./App";
import "./styles.css";
// put component into html page
ReactDOM.render(
<App msg="I like cheese" cheese={myCheese} />,
document.getElementById("app")
);
webpack.config.base.js
const path = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");
module.exports = {
entry: "./src/index.js",
output: {
path: path.join(__dirname, "dist"),
filename: "app.bundle.js",
},
module: {
...
},
plugins: [
new HtmlWebpackPlugin({
template: "./src/index.html",
}),
],
};
Any help is greatly appreciated. Thanks.
You have myCheese in App.js rather than index.js
Try moving this block of code into index.js
var myCheese = {
name: "Camembert",
smellFactor: "Extreme pong",
price: "3:50",
};
I have started to learn ReactJs, I dont have any idea how to debug this. I have a basic app.jsx .
var React = require('react');
var ReactDOM = require('react-dom');
var {Route, Router, IndexRoute, hashHistory} = require('react-router');
var Main = require('Main');
ReactDOM.render(
<Router history={hashHistory}>
<Route path="/" component={Main}>
</Route>
</Router>,
document.getElementById('app')
);
I have written two basic components in my React app now and I nested them.
var React = require('react');
React.createClass({
render: function () {
return (
<h2>Nav Component</h2>
);
}
})
module.exports = Nav;
var React = require('react');
var Nav = require('Nav');
var Main = React.createClass({
render: function () {
return (
<div>
<Nav/>
<h2>Main Component</h2>
</div>
);
}
});
module.exports = Main;
I use webpack
module.exports = {
entry: './app/app.jsx',
output: {
path: __dirname,
filename: './public/bundle.js'
},
resolve: {
root: __dirname,
alias: {
Main: 'app/components/Main.jsx',
Nav: 'app/components/Nav.jsx'
},
extensions: ['', '.js', '.jsx']
},
module: {
loaders: [
{
loader: 'babel-loader',
query: {
presets: ['react', 'es2015', 'stage-0']
},
test: /\.jsx?$/,
exclude:/(node_modules|bower_components)/
}
]
}
};
and I dont get any errors but browser shows nothing. When I check developer tools I see "Uncaught ReferenceError: Nav is not defined".The files are in correct folders. How can I solve this?
Thanks
If the code you’ve provided is accurate, the problem is that you didn’t actually define a variable called Nav in your nav file. You just called React.createClass without assigning that to the variable Nav. Then you tried to export Nav at the bottom. Assign your createClass calls to variables and it should solve your problem.
Hi because your component definition is wrong it could be like below
class Nav extends React.Component or var Nav = React.createClass({
render: function () {
return (
Nav Component
);
}
})
I have the following error with the below code, however I cannot identify what is wrong with my component. Any help is appreciated!
Error: Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: object. Check the render method of App.
index.js
import React, {Component} from 'react';
import ReactDOM from 'react-dom';
import YTSearch from 'youtube-api-search'; // Used to interact with Youtube API
import SearchBar from './components/search_bar'; // custom search bar component
import VideoList from './components/video_list'; // custom youtube video list component
const API_KEY = "key not shown here for privacy purposes";
class App extends Component {
constructor(props){
super(props);
this.state = {videos: []};
YTSearch({key: API_KEY, term: 'sufboards'}, (videos) => {
this.setState({videos});
});
}
render(){
return (
<div>
<SearchBar />
<VideoList videos={this.state.videos} />
</div>
);
}
}
ReactDOM.render(<App />, document.querySelector(".container"));
webpack.config.js
As requested by JordanHendrix.
module.exports = {
entry: [
'./src/index.js'
],
output: {
path: __dirname,
publicPath: '/',
filename: 'bundle.js'
},
module: {
loaders: [{
exclude: /node_modules/,
loader: 'babel'
}]
},
resolve: {
extensions: ['', '.js', '.jsx']
},
devServer: {
historyApiFallback: true,
contentBase: './'
}
};
video_detail.js
As requested by bhargavponnapalli
import React from 'react';
const VideoList = (props) => {
return (
<ul className="col-md-4 list-group">
{props.videos.length}
</ul>
);
};
export default VideoList;
search_bar.js
As requested by bhargavponnapalli
import React, {Component} from 'react';
class SearchBar extends Component {
constructor(props){
super(props);
this.state = {term: ""};
}
render(){
return (
<input
onChange={
event => this.setState({
term: event.target.value
})
}
value = {this.state.term}
/>
);
}
}
export default SearchBar;
Any extra code needed from my other components will be added here upon request.
Simple fix:
import VideoList from './components/video_list';
The file was empty, my code was in video_detail.js so I had to move it to the correct file, video_list.js
I’m trying to get react router dynamic routing to work by following this example: https://github.com/rackt/react-router/tree/master/examples/huge-apps
Here’s my setup:
webpack.config.js:
module.exports = {
devtool: 'inline-source-map',
entry: './js/app.js',
output: {
path: '../public',
filename: 'test-app.js',
chunkFilename: '[id].chunk.js',
publicPath: '/public/'
},
module: {
loaders: [
{
test: /\.js$/,
exclude: /node_modules/,
loader: 'babel',
query: {
presets: [
'es2015',
'react'
]
}
}
]
}
./js/app.js:
import React from 'react';
import ReactDOM from 'react-dom';
import { createHistory, useBasename } from 'history';
import { Router } from 'react-router';
const history = useBasename(createHistory)({
basename: '/'
});
const rootRoute = {
component: 'div',
childRoutes: [{
path: '/',
component: require('./components/App')
}]
};
ReactDOM.render(
<Router history={history} routes={rootRoute} />,
document.getElementById('root')
);
./components/App.js:
import React from 'react';
console.log('testing');
export default class App extends React.Component {
render() {
console.log('App');
return (
<div>
App!
</div>
)
}
}
index.html:
<!doctype html>
<html>
<head>
<title>Test App</title>
</head>
<body>
Hello
<div id="root"></div>
<script src="public/test-app.js"></script>
</body>
</html>
When I run the server, I see Hello displayed from index.html, I also see console.log('testing') from App.js, but the actual App.js component does not render. Any ideas why?
Thanks!
EDIT:
If I change ./components/App.js to ES5 syntax below, it works! Why is that? Does react router's component: require('./components/App') not work with ES6?
var React = require('react');
var App = React.createClass({
render: function() {
return (
<div>
App!
</div>
)
}
});
module.exports = App;
I think, you are using Babel 6, where they changed commonjs require syntax.
Now, you need to add the default:
component: require('./components/App').default
I had the same problem, finally found how to make it work.