How to put a function in route - reactjs

As a beginner, I'm trying to put my list of "clients" in a function to display in the route/component, is this possible?
App.js
render() {
return (
<div className = "App">
<div>
<AddCliente onAdd = {this.onAdd} />
</div>
<Router>
<div>
<Link to = "/">Cli</Link>
<Route path = "/" exact component = {Adde} />
</div>
</Router>
</div>
);
}
}
I wanna do this:
function Adde() {
return <div>
{
this.state.clientes.map(cliente => {
return (
<ClienteItem
key = {cliente.nome}
{...cliente}
onDelete = {this.onDelete}
/>
);
})
}
</div>;
}
export default Add;
Error:
TypeError: Cannot read property 'state' of undefined

You can do something like this in your component.
import React, { Component } from 'react';
class componentName extends Component {
constructor(props) {
super(props);
this.state = {
clients:[
{
name:'sdfd',
title:'sdfd'
}
]
};
}
Adde=()=>{
return(
<div>
{
this.state.clientes.map(cliente => {
return (
<ClienteItem
key = {cliente.nome}
{...cliente}
onDelete = {this.onDelete}
/>
);
})
}
</div>
);
}
render() {
return (
<div className = "App">
<div>
<AddCliente onAdd = {this.onAdd} />
</div>
<Router>
<div>
<Link to = "/">Cli</Link>
<Route path = "/" exact component = {Adde} />
</div>
</Router>
</div>
);
}
}
export default componentName;

Related

wrap component with span or div tag based on logic in react

what is the best way for me to use logic to wrap the component? I would like to have another span to wrap Child component if showSpan is true, maybe something like following, but it does not work
const Child = () => {
return <button>click me</button>;
};
const Home = (props: { showSpan: boolean }) => {
const { showSpan } = props;
return (
<div>
{showSpan && (<span> ssss)}
<Child />
{showSpan && (</span>)}
</div>
);
};
export default function App() {
return (
<div className="App">
<h1>
<Home showSpan={false} />
</h1>
</div>
);
}
You could use Fragment (empty tag) to be the alternative to span and use them as wrapper. Should work like this:
const Child = () => {
return <button>click me</button>;
};
const Home = (props: { showSpan: boolean }) => {
const { showSpan } = props;
const Wrapper = showSpan ?
({children}) => <span>ssss {children}</span> :
({children}) => <>{children}</>;
return (
<div>
<Wrapper>
<Child />
</Wrapper>
</div>
);
};
export default function App() {
return (
<div className="App">
<h1>
<Home showSpan={false} />
</h1>
</div>
);
}

Why is this.props.history undefined despite having used withRouter?

I'm trying to do this.props.history.push... in my component, but even after making sure that I'm exporting it using withRouter I still get this error:
Uncaught TypeError: Cannot read property 'push' of undefined
I also made sure that the parent component that's using this is wrapped inside of a ProtectedRoute as well:
// my component:
import React from 'react';
import { withRouter } from 'react-router-dom';
import { Link } from 'react-router-dom';
class UserIndexItem extends React.Component {
constructor(props) {
super(props);
this.handleClick = this.handleClick.bind(this);
this.play = this.play.bind(this);
}
handleClick(e) {
if (!e.target.classList.contains("triangle")) {
this.props.history.push(`/playlist/${this.props.playlist.id}`);
}
}
handleTrack(playlist) {
// still going forward one, then back one, and then it plays normally...
if (!playlist.payload.tracks) return;
let tracks = Object.values(playlist.payload.tracks);
let currentTrack = tracks[0];
let nextTrack = tracks[1];
this.props.receiveCurrentTrack(currentTrack);
this.props.receiveNextTrack(nextTrack);
this.props.receiveTitle(currentTrack.title);
this.props.receiveArtist(currentTrack.artist);
this.props.receiveAlbumId(currentTrack.album_id);
}
play() {
const { playlist } = this.props;
this.props.requestSinglePlaylist(this.props.playlist.id).then(playlist => this.handleTrack(playlist));
this.props.receivePlaylistId(playlist.id);
}
render() {
const { playlist } = this.props;
return (
<li>
<div className="playlist-image" onClick={ this.handleClick }>
<div className="play-button" onClick={ this.play }>
<div className="triangle right"></div>
<div className="circle"></div>
</div>
<div className="overlay"></div>
<img src={playlist.photo_url} alt="Playlist thumbnail" onClick={ this.handleClick }/>
</div>
<div className="playlist-name">
<Link to={`/playlist/${playlist.id}`}>{ playlist.title}</Link>
</div>
</li>
);
}
}
export default withRouter(UserIndexItem);
// my parent component:
import React from 'react';
import UserIndexItem from './user_index_item';
import { selectTracksFromPlaylist } from '../../reducers/selectors';
class UserIndex extends React.Component {
constructor(props) {
super(props);
}
render() {
const { user, playlists } = this.props;
return(
<div className="user-index-container">
<div className="header">
<h1>{ user.username }</h1>
<h2>Public Playlists</h2>
</div>
<div className="playlists">
<ul>
{ playlists.map(playlist =>
<UserIndexItem
key={ playlist.id }
playlist={ playlist }
requestSinglePlaylist={ this.props.requestSinglePlaylist }
receiveCurrentTrack={ this.props.receiveCurrentTrack }
receiveNextTrack = { this.props.receiveNextTrack }
receiveTitle={ this.props.receiveTitle }
receiveArtist={ this.props.receiveArtist }
receivePlaylistId={ this.props.receivePlaylistId }
receiveAlbumId={ this.props.receiveAlbumId }
/>)
}
</ul>
</div>
</div>
);
}
}
export default UserIndex;
// my route that's using the parent component:
<ProtectedRoute path="/users/:userId" component={UserIndex} />
// my ProtectedRoute implementation:
const Protected = ({ component: Component, path, loggedIn, exact }) => (
<Route path={ path } exact={ exact } render={ (props) => (
loggedIn ? (
<Component {...props} />
) : (
<Redirect to="/welcome" />
)
) }/>
);
You can try like this:
<ProtectedRoute path="/users/:userId" component={props => <UserIndex {...props} />} />
Please let me know if this is working.
Thanks.
I think that {...props} need to call inside UserIndexItem as well.
According to my understand inside the App.js you need to pass {...props} to child component otherwise it don't have parent properties
// this ProtectedRoute should change according to your requirement. I just put sample code
const ProtectedRoute = ({ component: Component, ...rest }) => (
<Route {...rest} render={(props) => (
? <Component {...props} />
: <Redirect to="/Login"/>
)} />
)
<ProtectedRoute path="/users/:userId" component={UserIndex} />
// my parent component:
<UserIndexItem
key={ playlist.id }
playlist={ playlist }
requestSinglePlaylist={ this.props.requestSinglePlaylist }
receiveCurrentTrack={ this.props.receiveCurrentTrack }
receiveNextTrack = { this.props.receiveNextTrack }
receiveTitle={ this.props.receiveTitle }
receiveArtist={ this.props.receiveArtist }
receivePlaylistId={ this.props.receivePlaylistId }
receiveAlbumId={ this.props.receiveAlbumId }
{...this.props}
/>

ReactJS Call Function of another Component react-router

I have implemented an app which uses react-router to handle the routes in my web-app. I want to trigger the function logintoggle which is on the Header.js component from a function from the Hompage.js component. The App.js has all the routes in one file.
Can anyone explain to me how this can be achieved with small code snippet?
App.js
render() {
const { location } = this.props;
return (
<IntlProvider
locale="a"
messages="s"
>
<Fragment>
<div>
<Headers />
<Switch>
<Route exact path="/women" component={HomePage} />
</Switch>
</div>
</Fragment>
</IntlProvider>
);
}
}
export default App;
Header
class Header extends React.Component {
constructor(props) {
super(props);
}
logintoggle(tab) {
if (this.state.activeTab !== tab) {
this.setState({
activeTab: tab
});
}
}
}
Homepage.js
class CheckOut extends Component {
constructor(props) {
super(props);
}
}
When you need to have a shared state among the components React.Context API is what you need. It allows you to create a separate context provider, which will provide the state and the methods to manipulate this state to all the components you need. In the example below I have a LoginContextProvider with activeTab state variable. I provide activeTab and setActiveTab to all the components inside LoginContextProvider's children. Header changes activeTab to 1, Homepage changes to 2 and LoginContextDebug represents the actual activeTab value.
const LoginContext = React.createContext(null);
const LoginContextProvider = ({ children }) => {
const [activeTab, setActiveTab] = React.useState(0);
return (
<LoginContext.Provider value={{ setActiveTab, activeTab }}>
{children}
</LoginContext.Provider>
);
};
const Header = () => {
// Use setActiveTab here
const { setActiveTab } = React.useContext(LoginContext);
return (
<div>
<h1>I am header</h1>
<button onClick={() => setActiveTab(1)}>Set activeTab to 1</button>
</div>
);
};
const Homepage = () => {
// Use setActiveTab here
const { setActiveTab } = React.useContext(LoginContext);
return (
<div>
<h1>I am homepage</h1>
<button onClick={() => setActiveTab(2)}>Set activeTab to 2</button>
</div>
);
};
const LoginContextDebug = () => {
const { activeTab } = React.useContext(LoginContext);
return (
<pre style={{ padding: 10, background: "lightgray" }}>
activeTab={activeTab}
</pre>
);
};
const App = () => (
<LoginContextProvider value={null}>
<Header />
<Homepage />
<LoginContextDebug />
</LoginContextProvider>
);
ReactDOM.render(<App />, document.getElementById('root'));
<script crossorigin src="https://unpkg.com/react#16/umd/react.production.min.js"></script>
<script crossorigin src="https://unpkg.com/react-dom#16/umd/react-dom.production.min.js"></script>
<div id="root"></div>

Transferring from one component (page) to another component ( another page)

what I am trying to achieve here is being able to move to Page1 component from App component by clicking a button.
The result I am getting is
Page 1
Let's get started
Go!
The result I want to achieve is
Page 1
Please point out what I am doing wrong here. Thank you.
import React, { Component } from 'react';
import Page1 from './comps/Page1';
class App extends Component {
state = {
page:0
}
HandlePage = () => {
this.setState({
page:1
})
}
render() {
let comp = null;
if(this.state.page === 1){
comp = <Page1/>
}
return (
<div className="App">
{comp}
<h1>Let's get started!!</h1>
<div className="button">
<button
type="submit"
onClick={this.HandlePage}
>GO</button>
</div>
</div>
);
}
}
export default App;
//Page 1 Component
import React, { Component } from 'react';
class Page1 extends Component {
render() {
return (
<div className="App">
<h1>Page 1</h1>
</div>
);
}
}
export default Page1;
Here is a snippet of how you can achieve it by conditional rendering:
const Component = React.Component;
class App extends Component {
state = {
page:0
}
handlePage = () => {
this.setState({
page:1
})
}
render() {
let Comp = null;
if(this.state.page === 1){
Comp = <Page1/>
} else if(this.state.page === 0) {
Comp = <StartPage handlePage={this.handlePage} />
}
return (
<div className="App">
{Comp}
</div>
);
}
}
function StartPage(props) {
return (
<div>
<h1>Let's get started!!</h1>
<div className="button">
<button
type="submit"
onClick={props.handlePage}
>GO</button>
</div>
</div>
);
}
class Page1 extends Component {
render() {
return (
<div className="App">
<h1>Page 1</h1>
</div>
);
}
}
ReactDOM.render(<App />, document.getElementById('root'));
<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="root"></div>
If you have more pages to display, I would encourage you to look at solution like React Router

React Native: showing/hiding the element on click

This might be a double of some question, but I couldn't find the answer to the specific question that I have. I have the following code:
import React, { Component } from 'react'
class FAQContent extends Component {
constructor(props) {
super(props);
this.state = {
opened: false,
};
this.toggleBox = this.toggleBox.bind(this);
}
toggleBox() {
const { opened } = this.state;
this.setState({
opened: !opened,
});
}
render() {
return (
<div>
<div className="question">
<div className="question-title" onClick={this.toggleBox}>
Title 1
</div>
{this.state.opened && (
<div class="answer">
Content 1
</div>
)}
</div>
<div className="question">
<div className="question-title" onClick={this.toggleBox}>
Title 2
</div>
{this.state.opened && (
<div class="answer">
Content 2
</div>
)}
</div>
</div>
)
}
}
export default FAQContent
This renders 2 question titles. However, when I click on any of the questions, the state change is triggered for all the questions. What is the most efficient way of showing the specific answer of the question without showing the rest of the components?
import React, { Component } from "react";
import { render } from "react-dom";
import { Link, BrowserRouter, Route } from "react-router-dom";
class App extends Component {
state = {
openedPost: "",
posts: [
{ question: "Question 1", id: 0, user: "lenny" },
{ question: "Question 2", id: 1, user: "benny" },
{ question: "Question 3", id: 2, user: "jenny" }
]
};
showPost = id => {
this.setState({ openedPost: id });
};
render() {
return (
<div>
<BrowserRouter>
<div>
<Route
path="/"
render={() => (
<Posts showPost={this.showPost} posts={this.state.posts} />
)}
/>
<Route
exact
path={`/posts/${this.state.openedPost}`}
render={() => (
<SinglePost
openedPost={this.state.openedPost}
showPost={this.showPost}
posts={this.state.posts}
/>
)}
/>
</div>
</BrowserRouter>
</div>
);
}
}
class Posts extends Component {
onClick = id => {
this.props.showPost(id);
};
render() {
const { posts, showPost } = this.props;
return (
<div>
{posts.map(item => (
<div onClick={() => this.onClick(item.id)}>
<Link to={`/posts/${item.id}`}>{item.question} </Link>{" "}
</div>
))}
</div>
);
}
}
class SinglePost extends Component {
render() {
const { posts, openedPost } = this.props;
const filtered = posts.filter(item => item.id === openedPost);
return (
<div>
{filtered.map(item => (
<div>
{" "}
QUESTION:{item.question} ID:{item.id}{" "}
</div>
))}
</div>
);
}
}
render(<App />, document.getElementById("root"));
Example
You are using a same state to control different parts. How about you make a new question component and let it to manage its own state and just use the question component in the FAQContent component.
Question component:
export default class Question extends Component {
state = { opened: false };
toggleBox = () => this.setState(state => ({ opened: !state.opened }));
render() {
return (
<div className="question">
<div className="question-title" onClick={this.toggleBox}>
{this.props.title}
</div>
{this.state.opened && (
<div class="answer">
{this.props.content}
</div>
)}
</div>
);
}
}
FAQContent Component:
const FAQContent = () => (
<div>
<Question title="title 1" content="content 1" />
<Question title="title 2" content="content 2" />
</div>
);
export default FAQContent;

Resources