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

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>

Related

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.

Trying to make a sub page (channel) in 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

React: unwanted multiple instances of same component

My Dashboard React component renders multiple child components. When I change the state of the parent component (dashboard), multiple instances of the child components are created. They are then stacked on top of each other:
as shown here
Obviously this is not what I want! Every component should only be displayed once.
Here is a simplified example:
state = {
goal : ''
}
_refresh = () => {
this.setState({
goal: '5'
})
}
render() {
return (
<div>
<div className='card'>
<div className='heading'>
<p style={{display: 'inline-block'}}>CURRENT WEIGHT</p>
{this.state.goal}
<button onClick={this._refresh}>hallo</button>
</div>
<CurrentPlot currentWeight={this.props.currentWeight} />
</div>
<div className='card'>
<div className='heading'>
<p>YOUR STATS</p>
</div>
<StatsPlot
xData={this.props.xData}
yData={this.props.yData}
/>
</div>
</div>
)
}
So whenever the button is clicked and the state is set, multiple instances of the plots are created.
And here is the root component from where the above component is rendered:
return (
<Switch>
<Route path='/dashboard' render={() => (
<Dashboard //all the props />
)}/>
more routes..
</Switch>
)
I would really appreciate any suggestions!

Resources