How come I can't navigate to the next page? - javascript

I'm trying to navigate to another component upon the Food Truck button being clicked. In the nextPage() function, I'm trying to make that happen but it just keeps throwing me an error.
How can I go from page to the next when clicking a button?
Note: I want to go to a totally different page, not stay on the same page.
import React, { Component } from "react";
import fire from "../../config/Fire";
import classes from "./Home.css";
import Aux from "../../hoc/Aux";
import Taco from "../../components/taco/Taco";
class Home extends Component {
constructor(props) {
super(props);
this.state = {
taco: {}
};
}
nextPage() {
return this.state.taco ? <Taco /> : <Home />;
}
render() {
return (
<Aux>
<h1 className={classes.ChooseTruck}>Choose your favorite truck!</h1>
<button
type="button"
className="btn btn-outline-primary btn-lg btn-block"
onClick={this.nextPage}
>
Food Truck
</button>
</Aux>
);
}
}
export default Home;

Hey guys I figured out what I did wrong :D Here's how you conditionally render if anyone else needs a reference on how to do so :D.
-I had to bind taco in the constructor i.e. this.taco = this.taco.bind(this);
-Create a state called flag and set it equal to false i.e. this.state {flag: false}
-Inside the nextPage() method, I had to set the state to true in order to be used later i.e. this.setState({flag: true});
-Inside render(), I set a variable called flag equal to the state of flag i.e. const flag = this.state.flag; which WAS initially false but afterwards set to true upon clicking the button which invokes nextPage()
-Finally, we check if flag is set equal true. If it's true, then return the component I'm trying to navigate to which's <Taco/>
import React, {Component} from 'react';
import fire from '../../config/Fire';
import classes from './Home.css';
import Aux from '../../hoc/Aux';
import Taco from '../../components/taco/Taco';
class Home extends Component {
constructor(props) {
super(props);
this.taco = this.taco.bind(this);
this.state = {
flag: false
}
}
nextPage() {
this.setState({flag: true});
}
render() {
const flag = this.state.flag;
if(flag) {
return <Taco/>;
}
return (
<Aux>
<h1 className={classes.ChooseTruck}>Choose your favorite truck!</h1>
<button
type="button"
className="btn btn-outline-primary btn-lg btn-block"
onClick={this.nextPage}>Food Truck
</button>
</Aux>
);
}
}
export default Home;

It is not possible to navigate to different screen with just pure React library. If you only use React without any navigation libraries, it means that you can only have a SPA(Single Page Application).
Try to research this github link https://github.com/ReactTraining/react-router. Or just navigate to the official documentation in here https://reacttraining.com/react-router/.

Related

Display a new component with button click

Im making my first react ptoject. Im new in JS, HTML, CSS and even web app programing.
What i try to do, is to display some infomration on button click.
I have an API, that looks like this:
endpoint: https://localhost:44344/api/Projects
My Data from it:
[{"id":1,"name":"Mini Jira","description":"Description for first project in list","tasks":null},{"id":2,"name":"Farm","description":"Description for second one","tasks":null}]
And im fine with that, i can get it easily by axios in my react app.
Now i will show you my Project.js Component:
import React, { Component } from "react";
import { ListGroupItem, Button, ButtonToolbar } from "react-bootstrap";
import ProjectDetails from "./ProjectDetails";
class Project extends Component {
render() {
return (
<ButtonToolbar>
<ListGroupItem>{this.props.project.name}</ListGroupItem>
<Button onClick={Here i want to display new component with details }bsStyle="primary">Details</Button>
</ButtonToolbar>
);
}
}
export default Project;
I have all data from api in project type.
My question is, how to display component that i named ProjectDetails.js on button click? I want to show all data stored in project from my api in separate view (new page or somethig like that).
View looks like this:
Thanks for any advices!
EDIT:
based on #Axnyff answer, i edited Project.js. it works ok. But when i want to (for testing) displat project.name, i get error map of undefined. My ProjectDetails.js:
import React, { Component } from "react";
class ProjectDetails extends Component {
state = {};
render() {
return <li>{this.props.project.name}</li>;
}
}
export default ProjectDetails;
EDIT2:
In Project.js in #Axnyff answet i just edited that line:
{this.state.showDetails && (
<ProjectDetails project={this.props.project} />
)}
i passed project by props, now it works like i want too. After click it displays project.name that i clicked on.
You should use state in your React component.
Let's create a field called showDetails in your state.
You can initialize it in your constructor with
constructor(props) {
super(props); // needed in javascript constructors
this.state = {
showDetails: false,
};
}
Then you need to modify the onClick to set that state to true
<Button onClick={() => this.setState({ showDetails : true })} bsStyle="primary">Details</Button>
And then use that state to show or not the ProjectDetails:
{ showDetails && <ProjectDetails /> }
The full component should look like
import React, { Component } from "react";
import { ListGroupItem, Button, ButtonToolbar } from "react-bootstrap";
import ProjectDetails from "./ProjectDetails";
class Project extends Component {
constructor(props) {
super(props); // needed in javascript constructors
this.state = {
showDetails: false,
};
}
render() {
return (
<ButtonToolbar>
<ListGroupItem>{this.props.project.name}</ListGroupItem>
<Button onClick={() => this.setState({ showDetails : true })} bsStyle="primary">Details</Button>
{ this.state.showDetails && <ProjectDetails /> }
</ButtonToolbar>
);
}
}
export default Project;
You can then modify the logic to add a toggling effect etc.
If you haven't done it, you should probably follow the official tutorial
function Bar() {
return <h1>I will be shown on click!</h1>;
}
class Foo extends React.Component {
constructor() {
super();
this.state = { showComponent: false };
}
handleClick = () => {
this.setState({ showComponent: !this.state.showComponent });
};
render() {
return (
<div>
{this.state.showComponent && <Bar />}
<button onClick={this.handleClick}>click</button>
</div>
);
}
}
ReactDOM.render(<Foo />, document.getElementById("root"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="root"></div>

Render a new Component without using router

I've created an application to React, and when it starts, the App component is rendered. I would like that when the user clicks on a button or link, the button or link has to be in the App component when clicking on that link, another component will be rendered but not inside the App component but only the new component will be rendered in the same URL. As for this new component, it has to have a similar button so that when the user clicks, only the App component is rendered and this component that the user has clicked on is not rendered, only the App component.
I do not know if I explained myself correctly. Ask me any question if you need some clarification.
My App component is the following:
import React, { Component } from 'react';
import Touch from './Touch';
import '../App.css';
class App extends Component{
render() {
return(
<div>
<div className="wrapper" >
<button >NewComponent</button><NewComponent />???
<h1>Google Cloud Speech with Socket.io</h1>
<p id="ResultText"><span className="greyText">No Speech to Text yet</span></p>
</div>
<div className="buttonWrapper" >
<button className="btn" id="startRecButton" type="button"> Start recording</button>
<button className="btn" id="stopRecButton" type="button"> Stop recording</button>
</div>
</div>
);
}
}
export default App
My index.js is the following:
import React from 'react';
import ReactDOM from 'react-dom';
import './App.css';
import App from './components/App.js';
import registerServiceWorker from './registerServiceWorker';
ReactDOM.render(<App />, document.getElementById('root'));
registerServiceWorker();
If you really don't want to use react-router you will need to store a value in the component's state and change the rendering method to reflect which button was pressed. If you want each of those component to include the button you need to switch, do the following :
class App extends Component {
constructor(props){
super(props);
this.state = {renderA: false,};
}
handleClick = (event) => {
this.setState((prevState) => ({renderA: !prevState.renderA}));
};
render = () => {
return(
<div>
{this.state.renderA ?
<ComponentA handleClick={this.handleCLick}/>:
<ComponentB handleClick={this.handleCLick}/>
}
</div>
);
};
} export default App;
// ComponentA
class ComponentA extends Component {
render = () => {
return(
<div>
// what you want inside your first page here
<button onClick={this.props.handleClick}
</div>
);
}
} export default ComponentA;
// ComponentB
class ComponentB extends Component {
render = () => {
return(
<div>
// what you want inside your second page here
<button onClick={this.props.handleClick}
</div>
);
}
} export default ComponentB;
But using react-router might also suits your case, and if you are going to write a large app, you should use it instead of rendering differents children components within the same one, based on users inputs.
If the URL stay the same, I don't think React-Router might help you.
If you want that App Component is not loaded, I think you should create two more Component, a Wrapper one, and the new component you want to display (from now on newComponent). What I suggest is:
Creating a property isButtonClicked inside the state of the Wrapper Component;
Creating a function handleButtonClick() inside the Wrapper Component:
handleButtonClick() => {
let isButtonClicked = !this.state.isButtonClicked;
this.setState({ isButtonClicked });
}
In the render() method of the Wrapper component, you write something like this:
render() {
if (this.state.isButtonClicked)
return <App />
else
return <NewComponent />
}
Then, in both App and NewComponent, if you click on the button, you call the this.props.handleButtonClick(), which will lead to a change of the state of Wrapper Component, therefore to a change of what is shown on the screen.

Add loader on button click in react/redux application

I'm trying to add a Loader as Higher-Order-Component on button click in react/redux application.
Already have working Loader component and styling, just need to set logic when button is clicked show loader and hide existing button.
Button component:
import React from 'react'
import '../../../styles/components/_statement-print.scss';
import Loader from './Loader';
const StatementPrint = (props) => {
return (
<div>
<button
className="print-statement-button"
onClick={props.handleStatementPrint}>PRINT
</button>
</div>
);
};
export default Loader(StatementPrint);
Loader:
import React, { Component} from 'react';
import '../../../styles/components/_loader.scss';
const Loader = (WrappedComponent) => {
return class Loader extends Component {
render() {
return this.props.handleStatementPrint // Where must be logic when to show loader or existing button component
? <button className="loader-button">
<div className="loader">
<span className="loader-text">LOADING...</span>
</div>
</button>
: <WrappedComponent {...this.props} />
}
}
}
export default Loader;
In Loader component i added comment where need to write logic when to set loader or button.
I followed this example: ReactCasts - Higher Order Components
I searched a lot of examples but most of them shows how to set loader then is data is fetching, but in my case i just need to show then onClick method is triggered.
So how to set logic when onClick method is fired? Is this is a good aproach? Also it will be better to try acomplish this doing with redux state, but don't know how to do this.
Any help will be appreciated.
You will have to make small modifications to achieve what you want.
The wrapper component Loader can have a isLoading state, on the basis of which you can decide whether to show the loader span or the wrapped component.
This state isLoading can be updated by the wrapped component by passing showLoader function as a prop.
Button component
import React from 'react'
import '../../../styles/components/_statement-print.scss';
import Loader from './Loader';
const StatementPrint = ({handleStatementPrint, showLoader}) => {
return (
<div>
<button
className="print-statement-button"
onClick={() => {
showLoader();
handleStatementPrint();
}}>
PRINT
</button>
</div>
);
};
export default Loader(StatementPrint);
Loader
import React, { Component} from 'react';
import '../../../styles/components/_loader.scss';
const Loader = (WrappedComponent) => {
return class Loader extends Component {
constructor(props) {
super(props);
this.state = {
isLoading: false
}
this.showLoader = this.showLoader.bind(this);
}
showLoader() {
this.setState({isLoading: true});
}
render() {
return this.state.isLoading
? <button className="loader-button">
<div className="loader">
<span className="loader-text">LOADING...</span>
</div>
</button>
: <WrappedComponent
{...this.props}
showLoader={this.showLoader}
/>
}
}
}
export default Loader;
EDIT
Since handleStatementPrint was required to be called, I have updated the click handler to include that function.
Also using de-structuring to avoid typing props repeatedly. See here for more info.
Just some external state is needed.
If you can't have external state (eg isLoading) than you could pass a function into a loader hoc which will derive isLoading from current props
Example: https://codesandbox.io/s/8n08qoo3j2

React-Redux Infinite loop because of possibly changing state [duplicate]

This question already has answers here:
Why do event handlers need to be references and not invocations?
(2 answers)
Closed 5 years ago.
Good afternoon,
In my class PageList I want to add a function that changes the state on click. However when I insert this function into the a button that doesnt even get clicked the browser starts a never ending loop changing the state of currentpage.
Even though I have read the docs about components this seems strange behaviour. The behaviour accurs when addPage button is clicked.
Thanks in advance!
PageList:
import React, {Component} from 'react';
import {bindActionCreators} from 'redux';
import {connect} from 'react-redux';
import Page from '../components/Page.jsx';
import {addPage} from '../actions/addPage.js'
import {nextPage} from '../actions/nextPage.js'
import RaisedButton from 'material-ui/RaisedButton';
import _ from 'lodash';
class PageList extends Component {
constructor(props){
super(props);
this.state = {
currentpage : 0,
};
}
nextPage(){
this.setState({currentpage: this.state.currentpage+1});
}
renderList() {
if(this.props.item){
return (
<div>
<RaisedButton label="Next Page" onClick={this.nextPage()}></RaisedButton>
<Page key={this.state.currentpage} index={this.state.currentpage}>
{this.props.item.title}
{this.props.item.desc}
</Page>
</div>
);
}else{
return(
<p>No Pages</p>
)
}
}
render() {
return (
<div>
<RaisedButton label="Add new Page" onClick={() => this.props.addPage("Titel Page", "Page Beschrijving")}></RaisedButton>
<ul>
{this.renderList()}
</ul>
</div>
);
}
}
// Get apps state and pass it as props to PageList
// > whenever state changes, the PageList will automatically re-render
function mapStateToProps(state, ownProps) {
return {
pageList: state.pageList,
item: _.find(state.pages, 'id', ownProps.currentpage)
};
}
// Get actions and pass them as props to to PageList
// > now PageList has this.props.selectPage
function matchDispatchToProps(dispatch){
return bindActionCreators({addPage: addPage, nextPage: nextPage}, dispatch);
}
// We don't want to return the plain PageList (component) anymore, we want to return the smart Container
// > PageList is now aware of state and actions
export default connect(mapStateToProps, matchDispatchToProps)(PageList);
You're calling the nextPage function on each render instead of passing it to onClick.
Change onClick={this.nextPage()} with onClick={() => this.nextPage()}
There is a little error:
<RaisedButton label="Next Page" onClick={this.nextPage}>
</RaisedButton>
otherwise this.nextPage() is called right when it is rendered.

Correct way to update form states in React?

So I'm having a go at my first React app using create-react-app, and I'm trying to make a multi-stage form based on this GitHub project. In particular the AccountFields and Registration parts.
That project seems to have been written in a much older version of React, so I've had to try and update it - and this is what I have so far:
App.js:
import React, { Component } from 'react';
import './App.css';
import Activity from './Activity';
var stage1Values = {
activity_name : "test"
};
class App extends Component {
constructor(props) {
super(props);
this.state = {
step: 1
};
};
render() {
switch (this.state) {
case 1:
return <Activity fieldValues={stage1Values} />;
}
};
saveStage1Values(activity_name) {
stage1Values.activity_name = activity_name;
};
nextStep() {
this.setState({
step : this.state.step + 1
})
};
}
export default App;
Activity.js:
import React, { Component } from 'react';
class Activity extends Component {
render() {
return (
<div className="App">
<div>
<label>Activity Name</label>
<input type="text" ref="activity_name" defaultValue={this.props.stage1Values} />
<button onClick={this.nextStep}>Save & Continue</button>
</div>
</div>
);
};
nextStep(event) {
event.preventDefault();
// Get values via this.refs
this.props.saveStage1Values(this.refs.activity_name.getDOMNode().value);
this.props.nextStep();
}
}
export default Activity;
I've looked at a number of examples, and this seems to be the right approach to store the current state (to allow users to go back and forth between different parts of the form), and to then store the values from this stage. When I click the Save & Continue button, I get an error saying Cannot read property 'props' of null. I mean obviously this means this is null, but I'm unsure of how to fix it.
Am I approaching this the wrong way? Every example I find seems to have a completely different implementation. I come from an Apache-based background, so this approach in general I find very unusual!
the this in nextStep isn't pointing to Activity and just do like this
<button onClick={()=>this.nextStep()}>Save & Continue</button>
Bind this to nextStep function:
<button onClick={this.nextStep.bind(this)}>Save & Continue</button>
Or in the constructor:
constructor(props){
super(props);
this.nextSteps = this.nextSteps.bind(this);
}

Categories

Resources