I am doing a simple react application and I have an App component which keeps track of the state and then renders it. At first the state it is an empty string. Afterwards when I access the /signin I click on a button that changes the state from "" to "Marc" and pass it via props to the Profile component who renders the name of the user on its page. The problem is that it does not change the state and it is always "". I tried to debug and the state is always "" but the method setState is actually called. So i do not know why. Can anyone help me? Thanks in advance and I enclose the code.
APP:
export default class App extends React.Component {
constructor(props) {
super(props);
this.state = {
session: ""
};
this.updateUser = this.updateUser.bind(this);
}
updateUser() {
this.setState({
session: "Marc"
});
}
render() {
return(
<BrowserRouter>
<Switch>
<Route path exact='/' component={Home}/>
<Route path='/profile' render={(props) => (
<Profile session={this.state.session} />
)}/>
<Route path='/signin' render={(props) => (
<SignIn onClick={this.updateUser} />
)}/>
</Switch>
</BrowserRouter>
);
}
}
SIGNIN:
export default class SignIn extends React.Component{
constructor(props) {
super(props);
this.handleClick = this.handleClick.bind(this);
}
responseGoogle (googleUser) {
const mail = googleUser.profileObj.email;
const familyName = googleUser.profileObj.familyName;
const name = googleUser.profileObj.name;
//this.changeName(mail);
alert("Mail: " + mail + "\n" + "Nom i Cognoms: " + name + "\nSuccessfully Logged In");
}
handleClick() {
this.props.onClick();
}
render () {
return (
<div>
<GoogleLogin
clientId="CLIENTID"
onSuccess={this.responseGoogle}
onFailure={this.responseGoogle}
buttonText="Google"/>
<button onClick={this.handleClick}>Instant User</button>
</div>
);
}
}
PROFILE:
export default class Profile extends React.Component {
constructor(props) {
super(props)
}
render() {
return(
<h1>I am {this.props.session} User</h1>
);
}
}
In your case when at the SignIn component, onClicking the button will update the State correctly, but when you try to visit another page say Profile by manually entering the URL in browser, your state change will be lost and the state will be reinitialized as you session has changed.
You should instead try to navigate Programatically , for which you could refer the following answer on StackOverflow:
Programatically Routing based on a condition with react-router
In short In SignIn component you will have
class SignIn extends React.Component {
...
handleClick() {
this.props.onClick();
this.props.history.push('/profile');
}
...
export default withRouter(SignIn);
The above is what I will recommend you to do, or else for testing you can have a Link component and navigate using that
render() {
return(
<BrowserRouter>
<div>
<Link to="/profile">Profile</Link>
<Switch>
<Route path exact='/' component={Home}/>
<Route path='/profile' render={(props) => (
<Profile session={this.state.session} />
)}/>
<Route path='/signin' render={(props) => (
<SignIn onClick={this.updateUser} />
)}/>
</Switch>
</div>
</BrowserRouter>
);
}
Related
I want react route to match for localhost:8945/?type=admin adddress.I tried with following code but it is always rendering Home component.
<BrowserRouter>
<Switch>
<Route exact path = "/?type=admin"> **this is not working**
<Admin />
</Route>
<Route exact path = "/">
<Home/>
</Route>
</Switch>
</BrowserRouter>
Whenever I type localhost:8945/?type=admin in url bar it should render Admin component (Without requiring any server api).
got solution !
class App extends React.Component{
constructor() {
super();
this.state = {
type:''
};
}
componentDidMount() {
this.setUrlParams();
}
setUrlParams(){
const urlParams = new URLSearchParams(window.location.search);
this.setState({type : urlParams.get('type')})
}
render(){
return {
<div>
{ this.state.type=== 'admin'
? <Admin/>
: <Home/>
}
</div>
}
}
}
Hi, check this out Query Params
I have three component namely App, Home and Menu. App is parent of Home and Menu. Home and Menu are siblings.
Menu component have some buttons, when user click on those buttons I want to change the state data of Home component. How to achieve this in React.js ?
App.js
function App() {
const [isMenu, setIsMenu] = useState(false);
let history = useHistory();
const changeIsMenu = () => {
setIsMenu(true);
}
return (
<div>
<div>
<Header id="myHeader"></Header>
</div>
<div className="content">
<Provider store={store}>
<div className="menu-other">
<Router>
{isMenu && <Menu></Menu>}
<Switch>
<Route exact path="/"
render={(props) => <Login history={history}
changeIsMenu={changeIsMenu} {...props} />}
/>
<Route exact path="/signup"
render={(props) => <Signup history={history}
changeIsMenu={changeIsMenu} {...props} />}
/>
<Route exact path="/home" component={Home}>
</Route>
<Route exact path="/create" component={Create}>
</Route>
<Route exact path="/about" component={About}>
</Route>
</Switch>
</Router>
</div>
</Provider>
</div>
</div>
);
}
Menu.js
class Menu extends React.Component
{
constructor(props)
{
super(props);
this.changeShow=this.changeShow.bind(this);
}
changeShow(option,event)
{
//I want to call a function of Home Component here
}
render(){
//here I capture the event and call the changeShow() function
}
}
Home.js
class Home extends React.Component {
constructor(props) {
super(props);
console.log("in constructor props =", this.props.mainData);
this.state = {
data: null,
isFetch: false,
clickEvent: false
}
this.allDataShow = this.allDataShow.bind(this);
this.upcomingShow = this.upcomingShow.bind(this);
}
allDataShow(){
allData(this.props.mainData);
}
upcomingShow(){
upcoming(this.props.mainData);
}
//I want to call this function from Menu component which is responsible to
//change the state data of Home Component
changeData(option) {
console.log("I'm home changeData");
switch (option) {
case "All":
console.log("All");
this.allDataShow();
break;
case "Upcoming":
console.log("Upcoming");
this.upcomingShow();
break;
case "Today":
console.log("Today");
todayData();
break;
case "Next 7 days":
console.log("Next 7 days");
next7Days();
break;
case "GoTo Date":
console.log("GoTo Date");
gotoDate();
break;
case "Search":
console.log("Search");
search();
break;
case "Filter":
console.log("Filter");
break;
case "Notify me":
console.log("Notify me");
break;
default:
console.log("default is here");
}
}
render(){
//here I display the state of Home Component
}
}
This is the code. I want to call a showData function of Home component from Menu component which is responsible to change the state data of Home component.
You are sending changeIsMenu a prop to both components inside the render method, so the only thing you need now is to use this function inside your component using its props:
changeShow(option,event)
{
//I want to call a function of Home Component here
this.props.changeIsMenu()
}
Not using your example as so many other things also there, so making it very straightforward with basic code. Please bear with me I have used the function component in the example. You can do the same in Class based component.
Stackblitz link
Explaination: I passed flag to Home Component, and a setFlag to Menu Component. In Menu Component calling setFlag on button click t.
App.js
const BasicExample = () => {
const [flag, setFlag] = useState(false);
return (
<Router>
<div>
<Menu setFlag={value => setFlag(value)} />
<hr />
<Route
exact
path="/"
render={props => <Home flag={flag} {...props} />}
/>
</div>
</Router>
);
};
Menu.js
const Menu = ({ setFlag }) => (
<div>
<h2>Menu</h2>
<input type="button" value="Click" onClick={() => setFlag(true)} />
</div>
);
export default Menu;
Home.js
const Home = ({ flag }) => (
<div>
<h2>Home</h2>
{flag ? "Menu button is clicked" : "Menu button is not clicked"}
</div>
);
export default Home;
I am having trouble with the Route path <Route path="customers/:id" render={(props) => <CusDataForm {...props}/>}/> in the code below:
import CusDataCtrl from './cusdata/CusDataCtrl'
import CusDataForm from './cusdata/CusDataForm'
class App extends Component {
render() {
return (
<BrowserRouter>
<Switch>
<Route exact path="/customers" component={CusDataCtrl} />
<Route path="customers/:id" render={(props) => <CusDataForm {...props}/>}/>
</Switch>
</BrowserRouter>
);
}
}
export default App;
if I use <Route exact path="/customers/:id" component={CusDataForm} /> the component does render correctly; however, I need to pass some props down to this component.
My calling component is defined like so:
class CusDataGrid extends Component {
constructor(props) {
super(props)
this.state = {data: []}
}
componentDidMount() {
let me = this;
dbFetch("customers",data => me.setState({data:data}));
}
callEdit = e => {
let recid = e.target.getAttribute("data")
this.props.history.push("/customers/"+recid);
}
render() {
const rows = this.state.data.map((row, ndx) => {
return (
<div key={ndx}><button data={row.recordid} className="waves-effect waves-light btn-small" onClick={this.callEdit}>Edit</button></div>
);
});
return (
<div id="cusdata"><div className="data-scrollable">{rows}</div></div>
);
}
};
export default CusDataGrid;
and my target component is:
class CusDataForm extends Component{
componentDidMount = () =>{
this.setState({id: this.props.id ? this.props.id : ""});
}
render(){
return(<div>HELLO</div>)
}
}
export default CusDataForm;
Please let me know what I am doing incorrectly. Thanks!
you can use hook useParams for it
<Switch>
<Route path="/:id" children={<Child />} />
</Switch>
function Child() {
// We can use the `useParams` hook here to access
// the dynamic pieces of the URL.
let { id } = useParams();
return (
<div>
<h3>ID: {id}</h3>
</div>
);
}
official documentation
The app.js file of my project is following. For all other components I used this.props.history.push('/') to redirect to the specific path and it works as those components receives the props. But in this app.js I have tried to console the props values inside constructor, componentWillMount and render but all gives null array. Is there any way to use this.props.history.push('/') inside app.js ?
class App extends Component {
constructor(props) {
super(props);
this.state = {};
console.log(this.props)
}
componentWillMount(){
console.log(this.props)
this.props.history.push('/')
}
render() {
console.log(this.props)
return (
<Router>
<div className="App">
<Route exact path='/' render={(props) => <Login {...props} />} />
<Route exact path='/dashboard' render={(props) => <Dashboard {...props}/>}/>
</div>
</Router>
);
}
}
export default App;
use withRouter
import { withRouter } from 'react-router-dom'
class App extends Component {
constructor(props) {
super(props);
this.state = {};
console.log(this.props)
}
componentWillMount(){
console.log(this.props)
this.props.history.push('/')
}
render() {
console.log(this.props)
return (
<Router>
<div className="App">
<Route exact path='/' render={(props) => <Login {...props} />} />
<Route exact path='/dashboard' render={(props) => <Dashboard {...props}/>}/>
</div>
</Router>
);
}
}
export default withRouter(App);
that will give you access to the history object and allow you to push to new routes. (I tested and verified before posting, so I know this works).
import it on the top of the file, then wrap App with it in the export default
I am rendering a Home component inside a Route so that I can pass state in as a prop to the component.
class App extends React.Component {
constructor(props){
super(props)
this.state = {
page: 'false'
};
}
render() {
return (
<Router>
<div>
<Switch>
<Route exact path='/' render={()=><Home page={this.state.page}/>} />
<Route exact path='/projects' component={Projects} />
<Route render={function(){
return <p>Not Found</p>
}} />
</Switch>
</div>
</Router>
)
}
}
Inside the Home component, I want to trigger a route change from a function. Because the Component is rendered inside the Route the history prop doesn't get passed in and therefore I cannot trigger a route change like so:
class Home extends React.Component{
constructor(props){
super(props);
this.gotoProjects = this.gotoProjects.bind(this);
}
gotoProjects() {
this.props.history.push('/projects');
}
render() {
return (
<button onClick={this.gotoProjects.bind(this)}>Projects</button>
)
}
}
How can I change routes from a component while still retaining it's props?
UPDATE
I've created a History.js using createBrowserHistory
import { createBrowserHistory } from 'history'
export default createBrowserHistory()
And updated App.js to be
import history from '../history';
class App extends React.Component {
constructor(props){
super(props)
this.state = {
page: 'false'
};
}
render() {
return (
<Router>
<div>
<Switch>
<Route exact path='/' render={()=><Home history={history} page={this.state.page}/>} />
<Route exact path='/projects' component={Projects} />
<Route render={function(){
return <p>Not Found</p>
}} />
</Switch>
</div>
</Router>
)
}
}
So now when I click the button in Home the url goes to /projects but the view is still rendering Home instead of Projects. How do I render Projects after the history.push happens?