I have written a multipage app using ReactJS. When a page/component with an is re-rendered, the browser memory increases. It seems the memory is not cleared when the component is unmounted. I expect the browser memory to decrease when the component is unmounted. Does anyone have a suggestion how to clear the memory for this image at unmount?
thanks,
Tim
import React from 'react';
export class About extends React.Component {
constructor(props) {
super(props);
}
componentDidMount() {
}
componentWillUnmount() {
}
render() {
return (
<div id='about' >
<div className="container">
<div className="row">
<div className="col-md-6">
<h2>title</h2>
<p>getting your ideas made</p>
</div>
<div className="col-md-6">
<img src="app/images/pic3.png" alt=""/>
</div>
</div>
</div>
</div>
)
}
}
update:
Below is the Parent component that the page is mounted to:
import React from 'react';
import ReactDOM from 'react-dom';
import {RightPane} from './components/RightPane.js'
import {LeftPane} from './components/LeftPane.js'
import {ModelLibrary} from './components/ModelLibrary.js'
import {ProjectsListing} from './components/ProjectsListing.js'
import {About} from './components/page_about.js'
import {Renderer} from './components/Renderer.js'
function MainSwitch(view){
switch (view) {
case 'listing':
return <ProjectsListing />
break;
case 'viewer':
return (
<div>
<Renderer />
<LeftPane />
<RightPane />
</div>
)
break;
case 'about':
return <About />
break;
default:
return (
<div>
<Renderer />
</div>
)
}
}
export class ReactRoot extends React.Component {
constructor(props) {
super(props);
this.state={
mainpage:''
}
}
showPage = (event)=>{
console.log(event.detail);
this.setState({
mainpage:event.detail
})
}
componentDidMount(){
window.addEventListener('page-change', this.showPage, false);
}
componentWillUnMount(){
window.removeEventListener('page-change', this.showPage, false);
}
render() {
return (
<div >
<div id='mainpage'>
{MainSwitch(this.state.mainpage)}
</div>
</div>
);
}
}
Related
I'm building a website using React and I'm trying to redirect the user to the index page after the login, but my component is not rendering anything, although I'm being redirected and I can see the URL changing from /welcome#/login to /main.
Since I'm not getting any error messages and the webpack is being successfully compiled, I can't see what's wrong anymore.
Any ideas of what could possibly be wrong?
Thank you very much!
Start.js
import React from "react";
import ReactDOM from "react-dom";
import Welcome from "./welcome";
import { App } from "./app";
import { Provider } from "react-redux";
import { createStore, applyMiddleware } from "redux";
import reduxPromise from "redux-promise";
import { composeWithDevTools } from "redux-devtools-extension";
import reducer from "./reducer";
const store = createStore(
reducer,
composeWithDevTools(applyMiddleware(reduxPromise))
);
let element;
if (location.pathname === "/welcome") {
element = <Welcome />;
} else {
init(store);
element = (
<Provider store={store}>
<App />
</Provider>
);
}
ReactDOM.render(element, document.querySelector("main"));
Welcome.js
import React from "react";
import Register from "./register";
import Login from "./login";
import { HashRouter, Route, Redirect } from "react-router-dom";
export default class Welcome extends React.Component {
constructor(props) {
super(props);
}
render() {
return (
<HashRouter>
<div className="register-wrapper">
<div>
<Route path="/login" component={Login} />
<Route exact path="/" component={Register} />
</div>
</div>
</HashRouter>
);
}
}
Login Component
import React from "react";
import axios from "./axios";
export default class Login extends React.Component {
constructor(props) {
super(props);
this.state = { error: false };
this.loginButton = this.loginButton.bind(this);
this.handleChange = this.handleChange.bind(this);
}
loginButton(e) {
e.preventDefault();
axios
.post("/login", this.state)
.then(res => {
if (res.data.success) {
location.replace("/main");
} else {
this.setState({
error: true
});
}
})
.catch(error => console.log(error));
}
handleChange(e) {
this.setState(
{
[e.target.name]: e.target.value
},
() => console.log("this.state:", this.state)
);
}
render() {
return (
<div className="login-main-container">
{this.state.error && <h2>Ops! Something went wrong.</h2>}
<h1 className="login-title">Kathi & Rodolfo</h1>
<h2 className="login-subtitle">Dear guest, please login first</h2>
<div className="login-container">
<form className="login-form">
<label className="label-login" htmlFor="email"> username </label>
<input className="input-login"
name="email"
placeholder="Best Couple You Know"
onChange={this.handleChange}
/>
<label className="label-login" htmlFor="password"> password </label>
<input className="input-login"
name="password"
type="password"
placeholder="Super Loving Password"
onChange={this.handleChange}
/>
<button
className="login-button"
onClick={this.loginButton}
>
Login
</button>
</form>
</div>
<h4 className="login-info">Information about username and password can be found on the Save The Date card</h4>
</div>
);
}
}
Index Component (Main)
import React from "react";
export default class Main extends React.Component {
constructor(props) {
super(props);
this.state ={ error: false};
}
render () {
return (
<div className="main-container">
<header>
<p>the wedding</p>
<p>rpsv</p>
<p>contact us</p>
<p>wedding gift</p>
</header>
{this.state.error && <h2>Ops! Something went wrong.</h2>}
<div className="save-the-date-img">
<h1>Save The Date</h1>
</div>
</div>
);
}
}
App.js
import React from "react";
import { BrowserRouter, Route, Link } from "react-router-dom";
import Main from "./main";
export class App extends React.Component {
constructor() {
super();
this.state = {};
}
render() {
return (
<BrowserRouter>
<div>
<Route exact path="/main" Component={Main}/>
</div>
</BrowserRouter>
);
}
}
location.replace("/main");
I think this line is wrong in your code.
While you are using React, you'd rather use react-router-dom's functionality than browser built-in feature.
Change the line to this.props.history.push('/main')
Give your file structure. Your component Login is not in BrowserRouter, but must be. Check the official sample: https://reacttraining.com/react-router/web/guides/quick-start.
instead of
location.replace("/main");
use
history.push("/main")
I've been working with React for the last days, so don't blame me.
But I'm trying to display my full name with a button but I get an error when I d this.
import React from 'react';
import logo from './logo.svg';
import './App.css';
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
name: 'Val',
surname: 'Vree',
age: 17,
nationality: 'Netherlands'
};
}
render() {
return (
<div>
<Header header={this.state.name} />
<Content content={this.state.surname} />
</div>
);
}
}
class Content extends React.Component {
render() {
return (
<div>
<p>I'm {this.props.content}</p>
</div>
);
}
}
export default App;
How can I put multiple variables in the Content class? Sorry for everything, because I been learning it for some days and I don't have some knowledge of React.
you can pass it in a few ways:
<Content content={ `${this.state.name} ${this.state.surname}`} />
or
<Content name={this.state.name} content={this.state.surname} />
and get
class Content extends React.Component {
render() {
return (
<div>
<p>I'm {this.props.name} {this.props.content}</p>
</div>
);
}
}
just add multiple props. if your feeling lazy want just one prop just pass this.state and you can pass the entire object. but this is bad practice generally.
hope this helps
import React from 'react';
import logo from './logo.svg';
import './App.css';
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
name: 'Val',
surname: 'Vree',
age: 17,
nationality: 'Netherlands'
};
}
render() {
return (
<div>
{/* <Header header={this.state.name} /> */}
<Content
name={this.state.name} //<---- add more props
surname={this.state.surname}
age={this.state.age}
nationality={this.state.nationality}
/>
</div>
);
}
}
class Content extends React.Component {
render() {
return (
<div>
<p>I'm {this.props.name} {this.props.surname}</p>
<p> I am {this.props.age} and i'm from {this.props.nationality}</p>
</div>
);
}
}
export default App;
When you say variables I think you mean props. You can pass props from a parent component to a child component like so
<ChildComponent propOne={this.state.stateOne} propTwo={this.state.stateTwo} />
Now ChildComponent has access to both of those props passed down from the parent component.
In ChildComponent you can access propOne by doing props.propOne (or this.props.propOne if ChildComponent is a class component).
In your case, you should do
import React from 'react';
import logo from './logo.svg';
import './App.css';
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
name: 'Val',
surname: 'Vree',
age: 17,
nationality: 'Netherlands'
};
}
render() {
return (
<div>
<Header header={this.state.name} />
<Content name={this.state.name} surname={this.state.surname} />
</div>
);
}
}
class Content extends React.Component {
render() {
return (
<div>
<p>I'm {this.props.name} {this.props.surname}</p>
</div>
);
}
}
export default App;
I got stuck with showing loading icon on initial page loading. The code looks fine for me but some how it doesn't shows the loading icon. I am using material ui RefreshIndicator for loading icon. I am using material-ui V^0.18.7.
Here is my initial App.js code
import React, { Component } from 'react';
import HeaderTemplate from './Layout/Components/Header';
import FooterTemplate from './Layout/Components/Footer';
import RefreshIndicator from 'material-ui/RefreshIndicator';
import RaisedButton from 'material-ui/RaisedButton';
import MuiThemeProvider from 'material-ui/styles/MuiThemeProvider';
class App extends Component {
constructor(props){
super(props);
this.state = {
showLoading: true
}
}
componentDidMount(){
this.setState({
showLoading: false
})
}
renderLoading(){
<RefreshIndicator
size={40}
left={10}
top={0}
status="loading"
style={{display: 'inline-block', position: 'relative'}}
/>
}
render() {
const muiTheme = imports.getMuiTheme({
});
return (
<MuiThemeProvider muiTheme={muiTheme}>
<div>
<HeaderTemplate logo="Postme" />
<div id="demo-settings" className="">
</div>
<div className="container-fluid bodyfluid">
{this.state.showLoading ? this.renderLoading(): ''}
{this.props.children}
</div>
<FooterTemplate />
</div>
</MuiThemeProvider>
);
}
}
export default App;
Your method renderLoading() doesn't return anything. It just creates the JSX-Element into "nothing".
import React, { Component } from 'react';
import HeaderTemplate from './Layout/Components/Header';
import FooterTemplate from './Layout/Components/Footer';
import RefreshIndicator from 'material-ui/RefreshIndicator';
import RaisedButton from 'material-ui/RaisedButton';
import MuiThemeProvider from 'material-ui/styles/MuiThemeProvider';
class App extends Component {
constructor(props){
super(props);
this.state = {
showLoading: true
}
}
componentDidMount(){
this.setState({
showLoading: false
})
}
renderLoading(){
return (<div style={{position: 'relative'}}>
<RefreshIndicator
size={40}
left={10}
top={0}
status="loading"
style={{display: 'inline-block', position: 'relative'}}
/>
</div>);
}
render() {
const muiTheme = imports.getMuiTheme({
});
return (
<MuiThemeProvider muiTheme={muiTheme}>
<div>
<HeaderTemplate logo="Postme" />
<div id="demo-settings" className="">
</div>
<div className="container-fluid bodyfluid">
{this.state.showLoading ? this.renderLoading(): ''}
{this.props.children}
</div>
<FooterTemplate />
</div>
</MuiThemeProvider>
);
}
}
export default App;
Now it returns the JSX element your created, and it should be rendered as you like.
I have a little big personal project, and I figured out (after 3 months of code) that none of my components ever unmount.
I created a new-react-app to test in a brand new environment, and it didn't work either.
Here's my class :
import React, { Component } from 'react';
import logo from './logo.svg';
import Test from './Test'
import './App.css';
class App extends Component {
constructor(props) {
super(props)
this.state = {
test: true
}
this.test = this.test.bind(this)
}
test(){
this.setState({
test: !this.state.test
})
}
render() {
return (
<div className="App">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<h1 className="App-title">Welcome to React</h1>
</header>
{this.state.test ? <Test /> :null}
<button onClick={this.test}/>
</div>
)
}
}
export default App;
here's console's result
console
Thank you for your time !
EDIT : I discovered that in every class I always called componentSWillUnmount instead of componentWillUnmount... thanks everybody
When you toggle the test state, your Test component does unmount. You maybe looking at some incorrect information. See the snippet below
class App extends React.Component {
constructor(props) {
super(props)
this.state = {
test: true
}
this.test = this.test.bind(this)
}
test(){
this.setState({
test: !this.state.test
})
}
render() {
return (
<div className="App">
<header className="App-header">
<h1 className="App-title">Welcome to React</h1>
</header>
{this.state.test ? <Test /> :null}
<button onClick={this.test}/>
</div>
)
}
}
class Test extends React.Component {
componentDidMount() {
console.log('mounted');
}
componentWillUnmount () {
console.log('unmounting');
}
render() {
return (
<div className="test">
Hello
</div>
)
}
}
ReactDOM.render(<App/>, document.getElementById('app'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="app"/>
I'm trying to figure out how to make components communicate with each other in React. I have a large component App. In it I have 2 components: ParentComponentOne and ParentComponentTwo. In ParentComponentOne I have a component called ChildParentOne. How can i render the ParentComponentTwo only when clicking on ChildParent One
App.jsx
import React, { Component } from 'react';
import ParentComponentOne from 'ParentComponentOne';
import ParentComponentTwo from 'ParentComponentTwo';
import './App.css';
class App extends Component {
state = {
show:{
componentTwo: false
}
};
render() {
return (
<div>
<ParentComponentOne />
{this.state.show.componentTwo? <ParentComponentTwo /> : null}
</div>
);
}
}
export default App;
ParentComponentOne.jsx
import React, { Component } from 'react';
import ChildParentOne from 'ChildParentOne';
class ParentComponentOne extends Component {
render() {
return (
<div>
<ChildParentOne />
<div>some content</div>
<ChildParentOne />
</div>
);
}
}
export default ParentComponentOne ;
ChildParentOne.jsx
import React, { Component } from 'react';
class ChildParentOne extends Component {
render() {
return (
<div onClick={}>
BTN
</div>
);
}
}
export default ChildParentOne ;
Pass a callback into ParentComponentOne which would change show.componentTwo state when child of it is clicked:
class App extends Component {
state = {
show: {
componentTwo: false
}
};
childClicked() {
this.setState({
show: {
componentTwo: true
}
})
}
render() {
return (
<div>
<ParentComponentOne childClicked={this.childClicked} />
{this.state.show.componentTwo? <ParentComponentTwo /> : null}
</div>
);
}
}
ParentComponentOne:
class ParentComponentOne extends Component {
render() {
return (
<div>
<ChildParentOne onBtnClick={this.props.childClicked} />
<div>some content</div>
<ChildParentOne onBtnClick={this.props.childClicked} />
</div>
);
}
}
Now, just pass this callback into ChildParentOne similarly and use it as a prop:
class ChildParentOne extends Component {
render() {
return (
<div onClick={this.props.onBtnClick}>
BTN
</div>
);
}
}