Trying to make a sub page (channel) in reactjs - reactjs

I am trying to make the user able to create channels in my web app.
If you the see image below, there is a modal that take the input and use
that as the id of the page that will newly created.
My route is specified as:
require('./styles/main.scss');
render(
<Router>
<div>
<Route exact path="/" component={Home}/>
<Route exact path="/RecTest" component={RecTest}/>
<Route exact path="/Example" component={Example}/>
<Route path="/channels/:id" component={ (props) => (<Channel {...props}/>)} />
</div>
</Router>,
// Define your router and replace <Home /> with it!
document.getElementById('app')
);
And the modal is coded as:
class MakeChannelModal extends Component {
constructor(props){
super(props);
console.log("constructor");
this.state={
channelName: ''
}
this.clickHandler = this.clickHandler.bind(this);
this.inputChangeHandler = this.inputChangeHandler.bind(this);
}
inputChangeHandler(event) {
this.setState({
channelName: event.target.value
})
}
clickHandler() {
<Link to={{ pathname: '/channels/' + this.state.channelName }}></Link>
}
render(){
return(
<div className="ui active modal">
<div className="header">Create a New Channel</div>
<div className="loginbody">
<div className="fillout">
<div className="channelName">
<span>Channel Name: </span>
<Input
onChange = { this.inputChangeHandler }
placeholder="Channel Name"
label = "Channel Name"
value = { this.state.channelName } />
</div>
</div>
<Button onClick = { this.clickHandler }>
SUBMIT
</Button>
</div>
</div>
)
}
}
export default MakeChannelModal
I was assuming this to take the channel name input and direct the page to a Channel component with the id of df.
My Channel component is just blank right now.
The thing is, if I click SUBMIT in the modal, it does not do anything.
Doesn't even show an error.
What am I doing wrong?

clickHandler() should be a function that changes pathname, making Router to draw another component, but it tries to draw React component by itself instead (not quite successfully though, because this function doesn't actually returns anything).
I believe you should either use props.history.push() in onClick(), or make <Button /> a <Link />.
Solution 1: (preferable, if you want a <Button>)
Replace your clickHandler() with this:
clickHandler() {
this.props.history.push('/channels/' + this.state.channelName);
}
Solution 2: (still would work)
Replace your <Button ... /> component with this:
<Link to={{ pathname: '/channels/' + this.state.channelName }}>
SUBMIT
</Link>
SO answer about history.push(): https://stackoverflow.com/a/43298961/6376451

Related

What's the best way to create a hamburger menu from scratch in Reactjs without using Hooks?

I'm trying to create a hamburger menu within React using state and onClick, from scratch. I have no experience with React Hooks so am trying to avoid that. The solution I have right now works, but is slow and glitchy and I have a feeling the code is quite flawed.
I deployed it anyways to test it out in live, and it's not working well at all in mobile chrome browser (https://vigilant-leavitt-a88a0e.netlify.app/). (though at least the background-color works when inspecting on a browser at mobile dimensions).
Can anyone tell me what I'm doing wrong here, or how this could be cleaned up? I have app.js feeding props to header.js.
Thank you!
App.js
export default class App extends React.Component {
constructor(props) {
super(props);
this.state = {
menuOpen: false
};
}
componentDidMount() {
this.setState({
menuOpen: false
});
}
handleMenuClick = () => {
this.setState({ menuOpen: true });
}
handleCloseMenuClick = () => {
this.setState({ menuOpen: false });
}
render() {
return (
<>
<Router>
<Header
menuOpen={this.state.menuOpen}
handleMenuClick={this.handleMenuClick}
handleCloseMenuClick={this.handleCloseMenuClick} />
<Switch>
<Route path="/resources"><Resources /></Route>
<Route path="/team"><Team /></Route>
<Route path="/faq"><Faq /></Route>
<Route path="/fees"><Fees /></Route>
<Route path="/"><Home /></Route>
</Switch>
<Footer />
</Router>
</>
);
}
}
Header.js
<div className="header__navburger">
{props.menuOpen === false ?
(<img
className="header__hamburger-icon"
alt="Menu"
src={menuicon}
onClick={() => props.handleMenuClick()}
/>) :
(<div className="header__navburger-close">
<img
className="header__close-icon"
alt="Close Menu"
src={closeicon}
onClick={() => props.handleCloseMenuClick()}
/>
<nav className="header__nav-list">
<Link to={`/home`} className="header__nav-link"
onClick={() => props.handleCloseMenuClick()}>Home</Link>
<Link to={`/resources`} className="header__nav-link"
onClick={() => props.handleCloseMenuClick()}>Patient Resources</Link>
<Link to={`/team`} className="header__nav-link"
onClick={() => props.handleCloseMenuClick()}>Meet the Team</Link>
<Link to={`/faq`} className="header__nav-link"
onClick={() => props.handleCloseMenuClick()}>FAQ</Link>
<Link to={`/fees`} className="header__nav-link"
onClick={() => props.handleCloseMenuClick()}>Fees</Link>
</nav>
</div>
)}
</div>
Did you mean icons of humburger menu changing slowly and glitchy? I've looked at the site and menu looks quite good for me.
First of all, there is no need in setState in your componentDidMount() as you should have the state set by this moment in constructor where initialization happens. This would force rendering the component twice with same state and be the reason that something works a little slow.
Second, do you use images for humburger menu icons? Downloading images takes some time as well, and I think that's why when clicking burger menu I don't see menu cross just in time. There are other ways to make menu like this, for exapmle it may be just
<div class="burger-menu">
<span></span>
</div>
and styles for span, span::before and ::after for white lines. You can also transform these lines to make a cross of it. I suggest this solution would allow things to work a little faster

How to pass static data from one component to another in React?

I have a plans component where I define the plan type, and I redirect to sign up component. I want to be able to show the plan type that the user has chosen, in my signup component?
I am trying to update the state like this:
export default class Plans extends Component {
constructor(props) {
super(props)
this.state = {
planType: '',
};
}
render() {
return (
<div>
<div className="billing_freq">Billed Monthly</div>
<form action="pro-invitation" method="post">
<input type="hidden" name="plan_type" value="monthly_pro" /> //I want to show this in signup
<div className="select_btn">
<input type="submit" name="submit" onClick={() => this.setState({planType: "monthly_pro"})} value="Invitation only" />
</div>
</form>
Signup: // a separate component
<label className="container"><span className="plan_name"></span> //PLAN TYPE HERE
</label>
class App extends Component {
render () {
return (
<BrowserRouter>
<div className="App">
<Switch>
<Route exact path='/plans' component={Plans} />
<Route exact path='/signup' component={Signup} />
</Switch>
</div>
</BrowserRouter>
How are you going to render Signup Component?
If from the routing, then there will be different way to achieve it and if you're using as a child component the pass as props like this -
<SignUp planType={this.state.planType} />
and access in Signup component as
<label className="container"><span className="plan_name"></span>{this.props.planType}
</label>
You want to give your planType state to the child component.
You can do this by doing this:
<Signup planType={this.state.planType} />
To use this in your child component use the props that you received from the parent, which is your planType state.
<label className="container"><span className="plan_name"></span>{this.props.planType}</label>

React component redirect with onClick of table row that already has another onClick

I have a table row that already has an onClick, which is used to send data to a api in order to render new content.. Presently I have that api rendering to the landing page. I would however like the data to render to a separate page/pathway.
Do I want to use Redirect, Link, another onClick, etc.. Just confused on where to start and the best method to use.
const SearchResults = props => (
<tbody>
{ props.contracts.map((contract, i) =>
<tr key={i} data-id={contract.Id}
onClick={() => props.handleContract(contract.Fields.filter(field => field.DataField==="IDXT001").map(field => field.DataValue))}
>{contract.Fields.map( docs =>
<td key={docs.Id}><span id={docs.DataField}>{docs.DataValue}</span></td>)}
</tr> )}
</tbody>
)
Here is my main class page. I would like the Pdfs to load on a new page.
<SearchResults
labels={this.state.labels}
contracts={this.state.contracts}
pdfs={this.state.pdfs}
handleContract={this.onClick}
/>
<Pdfs
labels={this.state.labels}
contracts={this.state.contracts}
pdfs={this.state.pdfs}
/>
Here is my App.js
class App extends Component {
render() {
return (
<div className="App">
<BrowserRouter>
<div>
<Header />
<Route exact path="/" component={Search} />
<Route path="/pdfs" component={Pdf} />
<Footer />
</div>
</BrowserRouter>
</div>
);
}
}
In your method you could use:
this.props.history.push({
pathname: '/yourpath',
state: { labels={this.state.labels}
contracts={this.state.contracts}
pdfs={this.state.pdfs} }
})
You can modify your onClick function to do some calculation on where you need to go based on where you are in the router history

Passing props.children from a container component to a presentational component

I'm doing some routing, I want to try to display IndexZoomOverviewContainer into IndexZoomViewPanelContainer.
When I go to the right path "...index/overview", IndexZoomViewPanelContainer is displayed, but when I'm passing the children (the Route for IndexZoomOverviewContainer in this case) from the container (IndexZoomViewPanelContainer) to the view (IndexZoomViewPanelComponent), it doesn't display it and gives me an error:
Error ScreenShot : https://i.gyazo.com/990f92d3058806baa576dca5247ace9e.png
When I removed this.props.children, its not showing any error.
Here is the routing:
<Route className="fullHeight fullWidth" key="indexzoom" path="index/" component={indexmonitor.IndexZoomViewPanelContainer} >
<Route className="fullHeight fullWidth" key="indexzoom1" path="overview" component={indexmonitor.IndexZoomOverviewContainer} />
<Route className="fullHeight fullWidth" key="indexzoom2" path={routes.INDEX_ZOOM_CONSTITUENTS_RELATIVE_PATH} component={dashboard.DashboardListContainer} />
</Route>
IndexZoomViewPanelContainer:
class IndexZoomViewPanelContainer extends React.Component {
constructor(props) {
super(props)
}
componentDidMount() {
}
componentWillUnmount() {
}
render() {
return <IndexZoomViewPanelComponent>
{this.props.children}
</IndexZoomViewPanelComponent>;
}
}
IndexZoomViewPanelComponent:
function IndexZoomViewPanelComponent(props) {
const tabs = getTabs();
return (
<div className="container">
<viewPanel.ViewPanel title={"Index Zoom"}
authKey={perm.INDEX_ZOOM_VIEWPANEL_PERM}
path={route.APP_PATH}
getPermStateFunc={(state) => state.MENUPERMS}
>
<TabControl tabs={tabs} selected={route.INDEX_ZOOM_OVERVIEW_RELATIVE_PATH}>
{props.children}
</TabControl>
</viewPanel.ViewPanel>
</div>
);
}
I want to try to display IndexZoomOverviewContainer into IndexZoomViewPanelContainer
<Route className="fullHeight fullWidth" key="indexzoom" path="index/"
component={indexmonitor.IndexZoomViewPanelContainer} >
IndexZoomViewPanelContainer renderd as a part of routing and it don't have any children
So,
return <IndexZoomViewPanelComponent>{this.props.children}</IndexZoomViewPanelComponent>
in the above script, this.props.children will be undefined and it will throw the error that you have shared.
In order to work this,it should be,
return <IndexZoomViewPanelComponent><IndexZoomOverviewContainer /></IndexZoomViewPanelComponent>
Here's a way to achieve what you need in the route :
// I'm renaming your components and removing className/key for readability
<Route path="/index" render={() => (
<IndexZoomViewPanelContainer>
<Route path="/index/overview" component={IndexZoomOverviewContainer} />
</IndexZoomViewPanelContainer>
)}
/>
You can also make your nested routes in IndexZoomViewPanelContainer component directly.
See https://reacttraining.com/react-router/core/api/Route/render-func for more infos.

React router 4 - detect if one of child route matches in a parent component

I am using react router 4 to display a list of users. The component Users loads when the route matches \Users. Inside that, I have a Route defined (user details) that's loaded when the URL matches \Users\:id.
The Users page has a grid/table with few columns.
render(){
const {users, flags} = this.props;
return (
<div>
<h3>Users</h3>
<div className="col-md-12">
<UsersGrid users={this.state.users} />
</div>
<Route path="/users/:id" component={UserDetail} />
</div>
)
}
What I want is if the user details route is active then to shrink the user grid (say apply class col-md-4) and show the user detail to its right.
But I am not sure how can I detect if a child route is active so that I can conditionally apply a class to an element. I tried using this.props.children but it is always undefined.
You would make use of matchPath from react-router
import { matchPath } from 'react-router'
render(){
const {users, flags, location } = this.props;
const match = matchPath(location.pathname, {
path: '/users/:id',
exact: false,
strict: false
})
return (
<div>
<h3>Users</h3>
<div className="col-md-12">
<UsersGrid users={this.state.users} />
</div>
<Route path="/users/:id" component={UserDetail} />
</div>
)
}
If url shows in address bar then you can check with window.location if it contains string like id after /user then perform action with condition check:
if(/user/{anyid}) {
*your condition action*
} else {
*else action*
}
you can use string regex to match the id.

Resources