I want to show the Logout button on the same row of the title but only when the user has made it to Home component.
In other words, I don't want to show the logout button at all times, especially when the user's at the login screen. I want it to show on the same row of the title only when they've logged in successfully and they're in Home
How would I achieve this? My head hurts from trying to make this work :(
Below's what I've tried so far, among other things.
import React, {Component} from 'react';
import classes from './Title.css';
import LogoutButton from '../../containers/LogoutButton/LogoutButton';
import Home from '../../components/Home/Home';
class Title extends Component {
constructor(props) {
super(props);
this.state = {
show: false,
showLogoutButton: true
};
}
showButton() {
this.setState({show: true});
if(this.state.show) {
return <LogoutButton/>;
} else {
return null;
}
}
render() {
return(
<div>
{ this.state.showLogoutButton ? this.showButton : null }
<h1 className={classes.Title}>Pick Ups</h1>
</div>
);
}
}
export default Title;
You can try something like below. You don't need to deal with function and modifying states.
You can simply do like below
import classes from './Title.css';
import LogoutButton from '../../containers/LogoutButton/LogoutButton';
import Home from '../../components/Home/Home';
class Title extends Component {
constructor(props) {
super(props);
this.state = {
showLogoutButton: this.props.authenticated
};
}
render() {
const { showLogoutButton } = this.state;
return(
<div className="row" style={{"display" :"flex"}}>
{ showLogoutButton && <LogoutButton/>}
<h1 className={classes.Title}>Pick Ups</h1>
</div>
);
}
}
export default Title;
Note: When you modify state using setState the state value will be updated only after render so you can't directly check immediately modifying the value.
Related
App.js
import React from 'react';
import './App.css'
import Tools from './components/class/Tools'
import Loading from './components/inc/Loading'
export default class App extends React.Component {
componentDidMount() {
Tools.showLoading(); // or new Tools();
}
render() {
return (
<div className="App">
<Loading />
</div>
)
}
}
Loading.js:
import React from 'react'
export default class Loading extends React.Component {
constructor(props) {
super(props)
this.state = {
display: 'none'
}
}
render() {
return (
<div className="loading" style={{display: this.state.display}}>
<span></span>
</div>
)
}
}
Tools.js
export default class Tools extends React.Component {
static showLoading(){ // or non-static
Loading.setState ...
}
}
I want change display state from outside of Loading component.
I use Loading in whole my project and I want create function for handle it.
Example for another use:
function xxx(){
Tools.showLoading(); // or new Tools();
}
Or:
<span onClick={Tools.showLoading(); // or new Tools();}></span>
Actually, I want create only one function to manage and handle display of Loading.
In Tools.js
let loadingStateSetter = null
export function setLoadingStateSetter(setter) {
loadingStateSetter = setter
return () => loadingStateSetter = null
}
export function setLoadingState(value) {
if (loadingStateSetter !== null) loadingStateSetter(value)
}
In Loading.js:
import { setLoadingStateSetter } from './Tools.js'
export default class Loading extends React.Component {
constructor(props) {
super(props)
this.state = {
display: 'none'
}
}
render() {
return (
<div className="loading" style={{display: this.state.display}}>
<span></span>
</div>
)
}
componentDidMount() {
this.removeStateSetter = setLoadStateSetter((value) => {
this.setState((state) => ({
...state,
display: value,
})
})
}
componentWillUnmount() {
this.removeStateSetter()
}
}
Usage:
import { setLoadingState } from './Tools.js'
function xxx(){
setLoadingState('some value')
}
While you can easily expose a setState function externally, it acts just like any other function, its not usually a good idea. You should instead consider rewriting your Loading component to use the property object to tell it if its loading and track the loading state higher up the component tree where it is accessible by things that would want to change its status.
I think you can using redux as store manager global state
https://redux.js.org/
another way pass it through props and handle it at parent component
I want the onClick event of the button in result.js to render my Spinner component, and have so far (kind of) gotten it to do so. At the moment, Spinner mostly has some console.log() statements, and it keeps logging "Rendered spinner." endlessly after clicking the button, about once every second.
For the record, the returned paragraph isn't being displayed, but I haven't gotten around to debugging that yet. Also, I have excluded some code in Result.js that I think is irrelevant.
For now, I just want Spinner to only render once after pressing the button. Any tips?
result.js:
import React, { Component } from "react";
import { connect } from "react-redux";
import Spinner from "./spinner";
class UnboxResult extends Component {
constructor(props) {
super(props);
this.state = {
showSpinner: false
};
this.handleUnboxClicked = this.handleUnboxClicked.bind(this);
}
handleUnboxClicked(event) {
event.preventDefault();
console.log("Inside handleUnboxClicked");
this.setState({
showSpinner: true
});
}
render() {
return (
<section className="opening">
<div className="container">
<div className="row">
<button onClick={this.handleUnboxClicked}>UNBOX</button>
</div>
<div className="row">
{this.state.showSpinner ?
<Spinner items={this.props.unbox.items}/> :
null}
</div>
</div>
</section>
);
}
}
export default connect(state => ({
unbox: state.unbox
}))(UnboxResult);
spinner.js:
import React, { Component } from 'react';
class Spinner extends Component {
constructor(props) {
console.log("Before super");
super(props);
console.log("Ran constructor.");
}
render(){
console.log("Rendered spinner.");
return(
<p>Spinning..</p>
);
}
}
export default Spinner;
You could add a handler method to update the state from spinner
handleClick(){
this.setState({
showSpinner: true
})
}
and in your render it will need to be passed as prop
<div className="row">
{this.state.showSpinner ?
<Spinner handleClick={this.handleClick}/> :
null}
</div>
In your spinner component return you can trigger this using onclick
<button onClick = {this.props.handleClick} > Click </button>
This will allow you to update the state back in your parent, You might want to figure out how you would display the items one at a time in spinner and only set state to false when there is no items left to display.
Sorry if i misunderstood your comment.
im having a real hard time learning react and I can't quite understand how to solve this problem. I have Tournaments.js which reads tournament names from an API and displays them as clickable elements with a reference to templates.js in which I would like to simply display the name of the element that was clicked.
Tournaments.js:
import React, { Component } from "react";
const API = 'http://localhost:8080/api/tournaments';
class Tournaments extends Component {
constructor() {
super();
this.state = {
data: [],
}
}
componentDidMount() {
fetch(API)
.then((Response) => Response.json())
.then((findresponse) => {
console.log(findresponse)
this.setState({
data:findresponse,
})
})
}
testfun(e) {
var target = e.target;
console.log(target)
}
render() {
return(
<div class="container">
<div class="row">
<div class="col-md-6 col-md-offset-3">
<div class="jumbotron text-center">
{
this.state.data.map((dynamicData, key) =>
<div>
<a key={dynamicData.id} href={"/#/template"} onClick={this.testfun}>{dynamicData.name}</a>
</div>
)
}
</div>
</div>
</div>
</div>
)
}
}
export default Tournaments;
template.js:
import React, { Component } from "react";
import Tournaments from "./Tournaments";
const API = 'http://localhost:8080/api/tournaments';
class template extends Component {
constructor() {
super();
this.state = {
data: [],
}
}
render() {
return(
<div>
<h1>clicked item</h1>
</div>
)
}
}
export default template;
And my API stores data looking like this:
[{"name":"abc","id":1,"organizer":"kla"},{"name":"fsdfs","id":2,"organizer":"fsdf"}]
I've tried to use onclick to get the value that was clicked but not sure how to display it in template.js.
Thanks for any help
I think you want to put user clicked item from Tournaments.js and display in Template.js
You can try to put Template inside Tournaments
Tournaments.js
import React, { Component } from "react";
import Template from './template';
class Tournaments extends Component {
constructor() {
super();
this.state = {
data: [],
clickedData: []
}
}
testfun(e) {
var target = e.target;
console.log(target);
let newClickedData = [];
newClickedData.push(target);
this.setState({
clickedData: newClickedData
});
}
render() {
return (
<div>
...
...
<Template clickedData={this.state.clickedData} />
</div>
);
}
}
export default Tournaments;
Template.js
import _ from 'lodash';
import React, { Component } from "react";
class template extends Component {
render() {
let clickedData = this.props.clickedData;
let displayClickedData = _.map(clickedData, (item) => {
return <div>item</div>;
});
return(
<div>
{displayClickedData}
</div>
)
}
}
export default template;
I would suggest picking one of the following options:
Wrap both Tournaments and Tournament in some parent component. Then if you click on any specific tournament, you can change its ID in state. If ID is null, you render list of tournaments, if ID is defined, you render your tournament component. That way you would lose the URL effect.
You can pass ID as GET parameter in URL and then read it in your Tournament component, so your code would look similar to this <a href={`/#/template?id=${dynamicData.id}`}>{dynamicData.name}</a>
You can try out React Router which would handle all that for you
I am trying to write a thing that lets the user move through posts. So you look at a particular post, and then you can go to the previous or next post. I am trying to do this with react router. So say the user looks at posts/3, then by clicking NEXT he or she will be redirected to posts/4 and then see post no. 4.
However, it does not work yet. Clicking the buttons works fine, and it also does change the URL in the browser. However, I do not know how I can then fetch a new post (and populate my currentPost reducer anew), whenever the route changes.
What I have so far is this:
import React from 'react'
import {connect} from 'react-redux'
import {fetchPost} from '../actions/currentPost.js'
class PostView extends React.Component {
constructor(props) {
super(props);
this.setNextPost = this.setNextPost.bind(this);
this.setPreviousPost = this.setPreviousPost.bind(this);
}
componentDidMount() {
const {id} = this.props.match.params;
this.props.fetchPost(id);
console.log("HELLO");
}
setPreviousPost() {
var {id} = this.props.match.params;
id--;
this.props.history.push('/Posts/1');
}
setNextPost() {
var {id} = this.props.match.params;
id++;
this.props.history.push('/Posts/'+id);
}
render() {
return (
<div>
<h1>Here is a Post</h1>
<button onClick={this.setPreviousPost}>Previous</button>
<button onClick={this.setNextPost}>Next</button>
</div>
);
}
}
function mapStateToProps (state) {
return {
currentPost: state.currentPost
};
}
export default connect(mapStateToProps, {fetchPost})(PostView);
The lifecycle method you're looking for is componentWillReceiveProps
Here's more or less what it would look like:
class Component extends React.Component {
componentWillReceiveProps(nextProps) {
const currentId = this.props.id
const nextId = nextProps.id
if (currentId !== nextId) {
this.props.fetchPost(nextId)
}
}
}
from there, I think Redux/React will handle the rest for you.
I have a landing page that contains a logo. I'm trying to get this logo to trigger a change of of state value. The purpose of this is to change from the landing page to the home page on click. I have set it up so that the landing page clear in an determined time, but I want to do this on click. This is my splash.js file that contains the on click function as well as the logo and landing page:
import React, { Component } from 'react';
import Woods from './woods.jpeg';
import Logo1 from './whitestar.png';
export default class Splash extends Component {
constructor() {
super();
this.toggleShowHome = this.toggleShowHome.bind(this);
}
toggleShowHome(property){
this.setState((prevState)=>({[property]:!prevState[property]}))
}
render() {
return(
<div id='Splashwrapper'>
<img src={Woods}></img>
<img id='logoc' src={Logo1} onClick={()=>this.toggleShowHome('showSquareOne')}></img>
</div>
);
}
}
I want the on click function to change the value of splash to false in my App.js file:
import React, { Component } from 'react';
import Splash from './splash';
import Menu from 'components/Global/Menu';
export default class About extends Component {
constructor(){
super();
this.state = {
splash: true
}
}
componentDidMount() {
setTimeout (() => {
this.setState({splash: false});
}, 10000);
}
render() {
if (this.state.splash) {
return <Splash />
}
const { children } = this.props; // eslint-disable-line
return (
<div className='About'>
<Menu />
{ children }
</div>
);
}
}
How can I link the on click function to the App.js file and change the value of splash?
You should define your function toggleShowHome in app.is and pass it as a prop to your splash component. Then you could change your local state in app.js
To make sure I'm understanding, you're looking for the image on the Splash component to trigger a change in the About component?
You can pass a method to your Splash component (from About) that it can call when the image is pressed. So something like this:
render() {
if(this.state.splash) {
return <Splash onLogoClicked={this.logoClicked.bind(this)} />
}
(.......)
}
logoClicked(foo) {
< change state here >
}
And then in your Splash component:
<img id='logoc' src={Logo1} onClick={this.props.onLogoClicked}></img>
Not sure if I understood you well, but you can try this: to pass the on click function from parent (About) to child (Splash), something like this:
YOUR MAIN APP:
export default class About extends Component {
constructor(){
super();
this.state = {
splash: true
}
this.changeSplashState = this.changeSplashState.bind(this);
}
//componentDidMount() {
//setTimeout (() => {
//this.setState({splash: false});
//}, 10000);
//}
changeSplashState() {
this.setState({splash: false});
}
render() {
if (this.state.splash) {
return <Splash triggerClickOnParent={this.changeSplashState} />
}
const { children } = this.props; // eslint-disable-line
return (
<div className='About'>
<Menu />
{ children }
</div>
);
}
}
YOUR SPLASH COMPONENT:
export default class Splash extends Component {
constructor() {
super();
//this.toggleShowHome = this.toggleShowHome.bind(this);
}
toggleShowHome(property){
this.setState((prevState)=>({[property]:!prevState[property]}));
//IT'S UP TO YOU TO DECIDE SETTING TIMOUT OR NOT HERE
//setTimeout (() => {
this.props.triggerClickOnParent();
//}, 10000);
}
render() {
return(
<div id='Splashwrapper'>
<img src={Woods}></img>
<img id='logoc' src={Logo1} onClick={this.toggleShowHome.bind(this,'showSquareOne')}></img>
</div>
);
}
}
Feel free to post here some errors or explain to me more about what you need, but that is the way it should look like, a standard way to pass function as props from parent to child.
You can also read more about how to pass props from parent to child/grandchild/many-deeper-level-child (of course in react's way):
Force React container to refresh data
Re-initializing class on redirect