Below is my react code. I have an edit profile route which allows editing the user profile. On completing the mutation request, I want to update the user details (user avatar, firstname and lastname) in header component. How is this done?
import React from 'react';
import Relay from 'react-relay';
import { IndexRoute, Route } from 'react-router';
import Header from './header';
import Sidebar from './sidebar';
import Footer from './footer';
import Query from './Query';
import EditProfile from './routes/Profile';
class App extends React.Component { render() {
return (
<Container {...this.props}>
<Sidebar />
<Header />
<div id='body'>
{this.props.children}
</div>
<Footer />
</Container>
); } }
export default (
<Route path='/' component={App}>
<IndexRoute component={EditProfile} queries={Query} />
</Route>
);
This is basic react communication, and there are several standard ways how to do that. You are already aware that you can pass data from parent to child by using props and refs (probably aware).
To achieve the communication other way around (from child to parent), standard and most simple way is to provide callback inside prop:
class SomeParent extends Component {
// This method is using es6 class properties
// in order to skip .bind(this)
handleChildFunc(someData) => {
console.log(someData)
}
render() {
return <SomeChild someFunc={this.handleChildFunc(this)} />
}
}
Then in the child component you can just do :
this.props.someFunc()
There are also other methods like using the redux/flux store and communicate trough them, using observer pattern etc.
More about this can be read here React component communication
Related
I am currently learning React and I am trying to create a simple modal that will display when the page loads. When I saved the changes, the page went to white and there aren't any errors in the console. I set the state to true and then tried calling it up in the render, thinking that this could be a way to do it. Can someone tell me what is it that I am doing wrong?
Modal.js
import React from 'react';
class Modal extends React.Component{
constructor(props){
super(props)
this.state = {open:true}
}
render(){
return (
<div open={this.state.open}>
<p>Hello</p>
</div>
)
}
}
export default Modal;
How I imported it into my app.js file
import React from 'react';
import HomePage from './components/HomePage'
import DadJokesApi from './components/DadJokesApi'
import SportsJokesApi from './components/SportsJokesApi'
import ProgrammingJokesApi from './components/ProgrammingJokesApi';
import { Route, Switch} from "react-router-dom";
import Modal from './components/Modal';
function App() {
return (
<main>
<Modal />
<Switch>
<Route path="/DadJokes" component={DadJokesApi} />
<Route path="/SportsJokes" component={SportsJokesApi} />
<Route path="/ProgrammingJokes" component={ProgrammingJokesApi} />
<Route path="/" component={HomePage} />
</Switch>
</main>
);
}
export default App;
Try to fix few issues in your code:
you are missing wrap your Routes with Router
the div has open prop which is not required
I have taken your code and made it work basic way. Go thru it and leave a comment for further doubts and I will edit my answer.
https://codesandbox.io/s/fragrant-frost-1hj6r?file=/src/App.js
Also, in your case, try to to maintain a state called open in your parent (eg: App.js) and pass it to your Modal component. In your app.js you can decide and turn the state open to off/on based on your loading condition.
I'm writing my first react application and I wanna use a Switch to show the component corresponding to the route. One of the routes uses a param. The problem is that the match attribute is missing from props so route matching doesn't seem to work (No component is inserted).
When I try to console.log this.props.match it returns undefined.
import { Switch, Route } from 'react-router-dom';
import React, { Component } from 'react';
import Index from './Index';
import Debate from './Debate';
class App extends Component {
componentDidMount() {
console.log(this.props.match); // I get undefined
}
render() {
return (
<div className="App">
<Switch>
<Route path="/debats" component={Index} />
<Route path="/debat/:debateSlug" component={Debate} />
</Switch>
</div>
);
}
}
export default withConfig(App);
I want to be able to access the match attribute so that the correct component is displayed.
Add to this in your Component
import {withRouter} from 'react-router-dom';
export default withRouter(withConfig(App));
I'm using react-router-dom: "4.3.1" with mobx, and try just redirect to my route.
After reading a lot similar questions I can't resolve this problem.
I've tried storing in state some flag and according to it use .
Tried use
this.props.history.push('....');
this.forceUpdate();
Tried wrap component with withRouter before mobx decorators and after.
With withRouter my component start inifinity rerender and my componentDidMound call api infinity times. (if I wrap after mobx)
I've tried many variants and this library still don't work properly.
// my main component
<Router basename={`/${baseName}`}>
<Provider store={store}>
...
</Provider>
</Router>
// my routes
<Switch>
<Route path="/home" component={ComponentA} />
<Route exact path="/a" component={ComponentB} />
<Route path="/a/:id" component={ComponentA} />
<Redirect to="/home" /> // this works normal
</Switch>
Usually react-router-dom just change browser url, but no component rerender, but with withRouter this start infinity api calls. How should I use this library with redirecting in any cases?
import { inject, observer } from 'mobx-react';
import * as React from 'react';
import { Col, PageHeader, Row, Well } from 'react-bootstrap';
import CompanyNew from './CompanyNew';
import { Company, InjectedProps } from '../../types';
interface CompanyNewPageProps extends InjectedProps {
history: HIstory
}
#inject('store')
#observer
export class CompanyNewPage extends React.Component<CompanyNewPageProps> {
public get injected() {
return this.props as InjectedProps;
}
public render() {
return (
<>
<PageHeader>Create new Company</PageHeader>
<Col className="col-lg-12">
<Row>
<Well>
<CompanyNew handleClose={this.itemAdded} />
</Well>
</Row>
</Col>
</>
);
}
public itemAdded = (company: Company) => {
this.props.history.push(`/companies/${company.id}`);
this.forceUpdate();
}
}
export default CompanyNewPage;
there example, this small component which is wrapper over another component, and after creating instance redirect to it. Item already exists on redirecting
I have made 3 components
1)Navbar
2)Content
3)Pagination
On home page I want to display all 3 components.
I have made another component Matchinfo which should get displayed when we click on view stats button (see screenshot for more clarification) .
In app.js how should I make use of Routes so that 3 components will get display on home page i.e localhost:3000/ and when I click on view stats button it should render component Matchinfo.
In app.js :
import React, { Component } from 'react';
import { Route, NavLink, HashRouter } from "react-router-dom";
import './App.css';
import Navbar from './components/navbar';
import Content from './components/content';
import Pagination from './components/pagination';
import Matchinfo from './components/matchinfo';
class App extends Component {
render() {
return (
<div className="App">
<div className="content">
<Route path="/" component={Navbar, Content, Pagination}/>
<Route path="/match" component={Matchinfo}/>
</div>
</div>
);
}
}
export default App;
You no need to call these components in app.js using routes. I would request you to create sepearte component like Home(see example below home.js).
Then, In app.js call Home component
import Home from './components/home';
<Route path="/" component={Home}/>
create home.js under components
Call Navbar, Content annd Pagination components in Home component
import React, {Component} from "react";
import Navbar from './components/navbar';
import Content from './components/content';
import Pagination from './components/pagination';
class Home extends Component {
constructor(props) {
super(props);
this.state = {
}
}
componentWillMount() {
}
render() {
return (
<div>
<Navbar/>
<Content />
<Pagination/>
</div>
)
}
}
export default Home;
Since you want to display Navbar, Content annd Pagination components in home page so do it like above way. Here Home is your parent component and Navbar, Content annd Pagination are child components to Home.
One route is enough mostly for one web page and in React most of times you will play with child components. You no need to configure all the components with routes.
There are several ways achieving the result.
The first one is using render method for home Route. Also, use exact attribute of Route to ensure the location is matched exactly.
import React, { Component } from 'react';
import { Route, NavLink, HashRouter } from "react-router-dom";
import './App.css';
import Navbar from './components/navbar';
import Content from './components/content';
import Pagination from './components/pagination';
import Matchinfo from './components/matchinfo';
class App extends Component {
render() {
return (
<div className="App">
<div className="content">
<Route path="/" render={(props) => (
<React.Fragment>
<Navbar/>
<Content />
<Pagination/>
<React.Fragment/>
)} exact/>
<Route path="/match" component={Matchinfo} exact/>
</div>
</div>
);
}
}
export default App;
The second one, create auxiliary component Home, for example, and include it in your route, like this:
<Route path="/" component={Home} exact/>
New to react and working with React Router so that I have many pages.
I am in my Home.jsx and it looks like this.
import React, { Component } from 'react';
import randomimage from '../imagefolder/rentalbackground.jpg';
import Header from './Header';
import Footer from './Footer';
import Rentals from './Rentals';
import {
BrowserRouter as Router,
Route,
Redirect,
Link
} from 'react-router-dom';
class Home extends Component {
render() {
return (
<div>
<Header />
<Router>
<div>
<Link to="/rentals">Rentals</Link>
<main>
<Route path="/" component={Rentals} />
</main>
</div>
</Router>
<p>some paragraph here</p>
<img src={randomimage} alt="imagerand" />
<Footer />
</div>
);
}
}
export default Home;
And my Rentals component looks like this.
import React, { Component } from 'react';
class Rentals extends Component {
render() {
return (
<div>
<p>this is for all the rentals</p>
</div>
)
}
}
export default Rentals;
What I am trying to do is create a page called localhost:3000/rentals which only displays the paragraph from the "Rentals" component in a new page. But when I click on the rentals link, which is on the Home.jsx, it displays all the components from the "Home" component including the picture, and the Header and the Footer components too.
I tried using exact path on the Route and nothing happens. How might I achieve this?
This is because you have placed your Router component inside your Home component which in turn have your Header and Footer. So all child components will be rendered inside your Home component.
Your router component should be on the top level of your App and all other components like Home, Rentals etc should be added as a child to the router.
Just to give you an example, it should be something like this.
//Your app initialisation, Top Level
ReactDOM.render(
<div style={{height: '100%'}}>
//All Your routes can be exported at one place and passed to your router as props. This will also help you maintain routes at one place
<Router history={browserHistory} children={routes}/>
</div>,
document.getElementById('root')
)
Will suggest you to read more about using React router and best practices since this is an architecture problem and quite broad topic to be answered here.