My app has 2 components: Location and User.
The locations are rendered when the page is loaded. Some locations have users. These users are loaded via an ajax call after the locations are rendered.
I wonder how I can render (conditionally) the user inside a location when that user is assigned to a location.
<App>
<location id="1" />
<location id="2" />
<Location id="3">
<User loactionId="3">
</User>
</Location id="4">
</App>
You can render Component dynamically using following example:
Method 1:
Here is the Location Component:
import React from "react";
import {User} from "./User";
export class Location extends React.Component {
render() {
return (
<div style={{margin:20, padding:20, color: '#FFFFFF', background: '#368BC1'}}>
This is Location Component {this.props.value}
{
this.props.user? <User/> : " No User Component"
}
</div>
);
}
}
Here is the User Component:
import React from "react";
export class User extends React.Component {
render() {
return (
<div style={{background: '#A0CFEC', padding: 20, color:'#000000'}}>
This is User Component
</div>
);
}
}
App Component:
import React from "react";
import ReactDOM from 'react-dom'
import {Location} from "./parent-child/Location";
class App extends React.Component {
render() {
return (
<div>
<Location user={true} value={1}/>
<Location user={false} value={2}/>
<Location user={true} value={3}/>
</div>
);
}
}
ReactDOM.render(<App/>, document.getElementById("root"));
export default App;
Method 2:
You can replace location Component with below code. Here I used React.createElement method to create Component dynamically.
import React from "react";
import {User} from "./User";
export class Location extends React.Component {
render() {
return (
<div style={{margin:20, padding:20, color: '#FFFFFF', background: '#368BC1'}}>
This is Location Component {this.props.value}
{
this.props.user? React.createElement(User, {propValue: 'Hello World'}, null) : " No User Component"
}
</div>
);
}
}
Related
I am trying to redirect to another router when the user clicks a specified button (named Navigate in this case) in a class-based component (named Counter). I am using <Navigate /> for that. It doesn't redirect to the page I specified to redirect to (path='/' for the homepage). In addition, I don't get any errors. Someone, please tell me the best way to use the <Navigate />.
For reference, the code is:
import React, {Component} from "react";
import {Navigate} from 'react-router-dom'
class Counter extends Component {
constructor(props){
super(props)
this.state = {
}
this.navigate = this.navigate.bind(this)
}
navigate(e){
return <Navigate to="/" />
}
render(){
return (
<div className='text-center'>
<h1>Hello there, this is a counter app</h1>
<button onClick={this.navigate} >Navigate</button>
</div>
)
}
}
export default Counter
You should try this. In your component navigate function cannot return Navigation. There are other methods for switching routes programmatically. Read this https://reactrouter.com/docs/en/v6/getting-started/concepts
import React, {Component} from "react";
import {Navigate} from 'react-router-dom'
class Counter extends Component {
constructor(props){
super(props)
this.state = {
dashboard: false,
}
this.navigate = this.navigate.bind(this)
}
navigate(e){
this.setState({dashboard:true})
}
render(){
return (
<div className='text-center'>
{this.state.dashboard && (
<Navigate to="/dashboard" replace={true} />
)}
<h1>Hello there, this is a counter app {this.state.dashboard && <span>dashboard</span>}</h1>
<button onClick={this.navigate} >Navigate</button>
</div>
)
}
}
export default Counter
I am learning React
While working on Props, I have created a component and using that component in my index.jsx. But the values passed through props are not displayed on the UI.
usingprops.jsx
import React from 'react';
class UsingProps extends React.Component {
render() {
return (
<div>
<p>{this.props.headerProp}</p>
<p>{this.props.contentProp}</p>
</div>
);
}
}
export default UsingProps;
index.jsx
import React from 'react';
import UsingProps from './Props/UsingProps.jsx';
class App extends React.Component {
render() {
return (
<div>
<UsingProps />
</div>
);
}
}
const myElement = <App headerProp="Header from props!!!" contentProp="Content from props!!!" />;
ReactDOM.render(myElement, document.getElementById('root'));
export default App;
You are putting the headerProp on the App component, not the UsingProps component, which is where you are trying to access it. You need to revise it to this:
class App extends React.Component {
render() {
return (
<div>
<UsingProps headerProp="Header from props!!!" contentProp="Content from props!!!" />
</div>
);
}
}
ReactDOM.render(<App />, document.getElementById('root'));
I'm working in nextjs.I have header component and in order to show header in all other pages ,overrided app.js with _app.js .Header has 2 navigation link usersList and users.
Now I want to send data from header component to another page say usersList and users on click of submit in header.How we can achieve that .
I know that we can use context .I'm using class based component don't know weather we can use context.
Is there any other solution to this problem..
Please help
header.js
class HeaderComponent extends Component {
onSearch(event){
//some code
}
render() {
return (
<div className="navbar">
<Input id="search-input" className="text-box" placeholder="Enter name or Email.." onKeyDown={($event)=>this.onSearch($event)} prefix={<Icon type="search" onClick={()=>this.onSearch} ></Icon>}></Input>
</div>
)
}
}
export default HeaderComponent
Layout.js
import React, { Component } from 'react';
import Header from './Header';
class Layout extends Component {
render () {
const { children } = this.props
return (
<div className='layout'>
<Header />
{children}
</div>
);
}
}
_app.js
import React from 'react';
import App from 'next/app';
import Layout from '../components/Layout';
export default class MyApp extends App {
render () {
const { Component, pageProps } = this.props
return (
<Layout>
<Component {...pageProps} />
</Layout>
)
}
}
userList.js
class AppUser extends Component {
render() {
return (
<Table
rowKey={data._id}
columns={this.columns1}
onExpand={this.onExpand}
dataSource={data}
/>
)
}
}
EDIT :
can we achieve it through props
You can use ReactRedux to create a store and have it accessible from all components.
https://redux.js.org/api/store [1]
I am learning react-router and trying to display a list of courses and course detail. But now, the CourseDetail2 component page does not display. Help!
App.js
`
import React, { Component } from 'react';
import axios from 'axios';
import CourseList2 from './components/CourseList2'
//campus data
const campusData = [
{ id: 1, value:'A',name: 'A' },
{ id: 2, value:'B',name: 'B' },
{ id: 3, value:'C',name: 'C' }
]
class App extends Component {
state={campus:null,
Courses:[]}
componentDidMount(){
//api call
setState={Courses:response.data}
}
//event handler
handleCampusChkChange()=>{
//code
}
render() {
return (
<div className="App">
<Campus key={item.id} {...item} onChange={this.handleCampusChkChange} />
<CourseList2 courses={this.state.Courses}/>
</div>
);
}
}
export default App;
`
CourseList2.js
import React from 'react';
import CourseDetail2 from './CourseDetail2';
import {BrowserRouter as Router, Route, Link,Redirect} from 'react-router-dom';
import './CourseItem.css';
import App from './App';
const CourseList2=({Courses})=>{
console.log("coruses="+Courses);
const renderedList= Courses.map(course=>{
return (<div className="item" >
<div class="content">
<div class="header">
<h4>
{course.SUBJECT} {course.CATALOG} {course.DESCR}
</h4> </div>
<Link to={{ pathname: 'course/'+course.ID}}
key={course.ID}>
View More
</Link>
</div>
</div>
)
});
return (
<Router><div className="List ui relaxed divided list">
{renderedList}
<Route path="course/:course.ID" component={CourseDetail2} />
</div></Router>);
}
export default CourseList2
CourseDetail2.js
import React, { Component } from 'react';
class CourseDetail2 extends Component {
render(){
return (
<div>
Course Detail: CLASS ID {this.props.match.params.ID}
</div>
);
}
};
export default CourseDetail2;
Adding as answer instead of comment.
Probably want to pass this.state.Courses to CourseList2, and wrap CourseDetails2 with withRouter HOC from react-router-dom so it can access the route match prop.
Also, the path in the route in CourseList2 should probably be path="course/:ID" since that is how you access it on the details.
location, match and history objects can only be accessed when you wrap the component with the higher order component withRouter.
Right now you don't have access to this.props.match in CourseDetail2 component.
import React, { Component } from 'react';
import {withRouter} from 'react-router';
class CourseDetail2 extends Component {
render(){
return (
<div>
Course Detail: CLASS ID {this.props.match.params.courseID}
</div>
);
}
};
export default withRouter(CourseDetail2);
Also the string after : doesn't have match with the code. It can be anything.
<Route path="course/:courseID" component={CourseDetail2} />
And you access using that string name in your code.
I have three js files. The parent I am to call the child classes. The code goes like this.
This is the parent class App.js
import React from 'react';
import ReactDOM from 'react-dom';
import $ from 'jquery';
import {FirstPage} from './FirstPage.js';
import {Panorama} from './Panorama.js';
import {BrowserRouter,Route,Router,Switch} from 'react-router-dom';
class App extends React.Component{
constructor(props){
super(props);
}
render(){
return(
<div>
<BrowserRouter>
<Switch>
<Route exact path="/" component={FirstPage} />
<Route path=":id" component={Panorama} />
</Switch>
</BrowserRouter>
</div>
)
}
}
ReactDOM.render(<App/>,document.getElementById('container'));
The FirstPage.js is something like this
import React from 'react';
import ReactDom from 'react-dom' ;
import $ from 'jquery' ;
import {Panorama} from './Panorama.js';
import {Redirect,Link} from 'react-router-dom';
import {withRouter} from 'react-router';
class FirstPage extends React.Component{
constructor(props){
super(props);
this.state={
list:[],
images:[],
isClicked:false,
redirect:true,
imageUrl:''
}
this.loadImages=this.loadImages.bind(this);
this.loadOne=this.loadOne.bind(this);
}
componentDidMount(){
window.addEventListener('load',this.loadImages);
}
loadImages(){
console.log("load");
var that=this;
$.ajax({
type:'GET',
url:'https://demo0813639.mockable.io/getPanos',
datatype:'jsonp',
success:function(result){
var images=that.state.images;
for(var i=0;i<result.length;i++){
that.state.images.push({"pano":result[i].pano,"name":result[i].name});
}
that.setState({
images:images
})
}
})
}
loadOne(pano){
console.log("pano: ",pano);
this.setState({
isClicked:true,
imageUrl:pano
})
//this.props.history.push(`/image/${pano}`)
}
render(){
var list=this.state.list;
console.log("Image URL: "+this.state.imageUrl);
return this.state.isClicked?<Link to={`${this.state.imageUrl}`}/>:
<div> {this.state.images.map((result)=>{
return(<div className="box">
<div className="label">{result.name}</div>
<img src={result.pano} className="image col-md-3" onClick={this.loadOne.bind(this,result.pano)}/>
</div>
)
})}
</div>
}
}
module.exports={
FirstPage:FirstPage
}
This page makes an ajax call and loads four images on the screen.If clicked on one of those images, another js file is supposed to be called with the id of that image so that the particular image can be seen in full screen.
import React from 'react';
import ReactDOM from 'react-dom';
import $ from 'jquery';
import {Link} from 'react-router-dom';
class Panorama extends React.Component{
render(){
console.log("Image: "+ props.match.params.id);
return(
<div>
<img src={`${props.match.params.id}`}/>
</div>
)
}
}
module.exports={
Panorama:Panorama
}
Although I get no errors in the console, after clicking on an image nothing is coming up on the screen. What is wrong with the code?
The version of React router is v4.
First thing you need to do as #Fawaz suggested, update your Route
<Route path="/panorama/:imageUrl" component={Panorama} />
As you are sending the url as parameter, you need to encode the url before loading image, and you can change the route using history API, no need to use the Link in your render method on some state change. I think the approach is wrong. I have updated the loadOne method as below:
loadOne(pano){
let imageUrl = encodeURIComponent(pano);
this.props.history.push(`/panorama/${imageUrl}`);
}
In Panorama Component, you can decode the url and load the image.
render() {
let url = decodeURIComponent(this.props.match.params.id);
return(
<div>
<img src={`${url}`}/>
</div>
)
}
FirstPage.js
import ReactDom from 'react-dom' ;
import $ from 'jquery' ;
import {Panorama} from './Panorama.js';
import {Redirect,Link} from 'react-router-dom';
import {withRouter} from 'react-router';
class FirstPage extends React.Component{
constructor(props){
super(props);
this.state={
images:[]
}
this.loadImages=this.loadImages.bind(this);
}
componentDidMount(){
window.addEventListener('load',this.loadImages);
}
loadImages(){
var that=this;
$.ajax({
type:'GET',
url:'https://demo0813639.mockable.io/getPanos',
datatype:'jsonp',
success:function(result){
that.setState({
images:result // I am assuming, result is array of objects.
})
}
})
}
loadOne(pano){
let imageUrl = encodeURIComponent(pano);
this.props.history.push(`/panorama/${imageUrl}`);
}
render(){
return <div>
{this.state.images.map((result)=>{
return(<div className="box">
<div className="label">{result.name}</div>
<img src={result.pano} className="image col-md-3"
onClick={this.loadOne.bind(this,result.pano)}/>
</div>)
})}
</div>
}
}
module.exports={
FirstPage:FirstPage
}
Your path needs to match the one you're calling. Change your second route to :
<Route path="/image/:id" component={Panorama} />