I know that it is happening because React is re-rendering the page and hence the input field is losing the focus. I have tried everything I could think of but none worked! I can't find a way to resolve the issue.
Here's my React code.
import React, { ChangeEvent, Component, ReactNode } from 'react'
import { Root, /*Routes*/ } from 'react-static'
import { Link } from '#reach/router'
import { Helmet } from 'react-helmet'
import './app.css'
// import FancyDiv from '#components/FancyDiv'
/* According to the following documentation,
* https://github.com/nozzle/react-static/blob/master/docs/concepts.md#writing-universal-node-safe-code
*/
let Sidenav = { init(_: any, options: any) { return {_, options} } }
let updateTextFields = () => {}
if (typeof window !== 'undefined') {
const materialize = require('materialize-css')
Sidenav = materialize.Sidenav
updateTextFields = () => materialize.updateTextFields()
}
interface IComponentProps {
}
interface IComponentState {
'long_url': string
}
const LongUrlInput = (props: any) =>
<input
key='in1'
id="long_url"
type="text"
className="validate"
onChange={ props.handleLongUrl }
/>
export default class App extends Component<IComponentProps, IComponentState> {
constructor(props: any) {
super(props)
this.state = {
'long_url': ''
}
}
componentDidMount(): void {
const elem = document.querySelectorAll('.sidenav')
Sidenav.init(elem, {})
updateTextFields()
}
handleLongUrl = (event: ChangeEvent<HTMLInputElement>): void => {
console.log('types', event.target.value, this.state.long_url)
this.setState({
'long_url': event.target.value
})
}
render(): ReactNode {
return (
<Root>
<Helmet>
<title>ShortURI - URL Shortener</title>
<meta name="description" content="Create short URLs and also monitor traffic with proper analysis report." />
</Helmet>
<nav className={'indigo'}>
<div className="nav-wrapper" style={{ padding: '0 20px' }}>
<Link to={'/'} className={'brand-logo'}>ShortURI</Link>
<a href={''} data-target="slide-out" className="sidenav-trigger">
<i className="material-icons">menu</i>
</a>
<ul id="nav-mobile" className="right hide-on-med-and-down">
<li><Link to={'/about'}>About</Link></li>
<li><Link to={'/#!'}>Login</Link></li>
<li><Link to={'/#!'}>Register</Link></li>
</ul>
</div>
</nav>
<ul id="slide-out" className="sidenav">
<li><a className="sidenav-close" href="#">Clicking this will close Sidenav</a></li>
</ul>
<div className="content">
<div className="row">
<div className="card">
<div className="card-content black-text">
<span className="card-title">Card Title</span>
<div className="input-field col s6">
<LongUrlInput handleLongUrl={this.handleLongUrl}/>
<label className="active" htmlFor="long_url">Long URL</label>
</div>
</div>
</div>
</div>
{/*<FancyDiv>*/}
{/*<Routes/>*/}
{/*</FancyDiv>*/}
</div>
</Root>
)
}
}
PS: I am new to React. Any help would be appreciated.
Note: Typing some random words to suppress StackOverflow Warning - "Looks like your question is mostly code, blah-blah".
I changed <Root>...</Root> to <div>...</div> and somehow it is now working. Weird!
Related
I am getting this error while I use state.clicked statement inside if-else condition.
Below is my code,
Hamburger.js
import React, { useEffect, useRef } from "react";
import { Link } from "react-router-dom";
const Hamburger = ({ state }) => {
let menu = useRef(null);
useEffect(() => {
if (state.clicked === false) {
//close our menu
menu.style.display = "none";
} else if (
state.clicked === true ||
(state.clicked === true && state.initial === null)
) {
// open our menu
menu.style.display = "block";
}
});
return (
<div ref={(el) => (menu = el)} className="hamburger-menu">
<div className="menu-secondary-background-color"></div>
<div className="menu-layer">
<div className="container">
<div className="wrapper">
<div className="menu-links">
<nav>
<ul>
<li>
<Link to="/opportunities">Opportunities</Link>
</li>
<li>
<Link to="/opportunities">Work</Link>
</li>
<li>
<Link to="/opportunities">Contact</Link>
</li>
</ul>
</nav>
</div>
</div>
</div>
</div>
</div>
);
};
export default Hamburger;
Header.js
import React, { useState } from "react";
import { Link } from "react-router-dom";
import Hamburger from "./Hamburger";
const Header = () => {
const [state, setState] = useState({
initial: false,
clicked: null,
menuName: "Menu",
});
const [disabled, setDisabled] = useState(false);
const handleMenu = () => {
disableMenu();
if (state.initial === false) {
setState({
inital: null,
clicked: true,
menuName: "Close",
});
} else if (state.clicked === true) {
setState({
clicked: !state.clicked,
menuName: "Menu",
});
} else if (state.clicked === false) {
setState({
clicked: !state.clicked,
menuName: "Close",
});
}
};
// Determine if our menu button should be disabled
const disableMenu = () => {
setDisabled(!disabled);
setTimeout(() => {
setDisabled(false);
}, 1200);
};
return (
<header>
<div className="container">
<div className="wrapper">
<div className="inner-header">
<div className="logo">
<Link to="/">Adarsh Goldar</Link>
</div>
<div className="menu">
<Link to="/">Home</Link>
<Link to="/">About</Link>
<button disabled={disabled} onClick={handleMenu}>
Menu
</button>
</div>
</div>
</div>
</div>
<Hamburger />
</header>
);
};
export default Header;
Yes because you have not passed state as a prop to do that change your code as below
in header.js
<Hamburger state={state}/>
well you need to pass state props to Your component:
<Hamburger state={state}/>
and for Hamburger you dont need to use useEffect and ref to update the style because when state props change the component will re render and every code will run again.
here how to do it with jsx style:
const Hamburger = ({ state }) => {
return (
<div style={{display:state.clicked?"block":"none"}} className="hamburger-menu">
<div className="menu-secondary-background-color"></div>
<div className="menu-layer">
<div className="container">
<div className="wrapper">
<div className="menu-links">
<nav>
<ul>
<li>
<Link to="/opportunities">Opportunities</Link>
</li>
<li>
<Link to="/opportunities">Work</Link>
</li>
<li>
<Link to="/opportunities">Contact</Link>
</li>
</ul>
</nav>
</div>
</div>
</div>
</div>
</div>
);
};
export default Hamburger;
and you can wrap Hamburger component in React.memo to prevent unnecessary re render so it will re render only when state props change : export default React.memo(Hamburger)`
In my react app I have this child component that inherits data from its parent. However, it does not update the page with new data from the child component when a relevant anchor link is clicked.
Here's my build - https://suite-search-lk.surge.sh/result/369523
From the link above if you click on a suggested card h1 element it just updates the URL with the id but does not update the page with the relevant card data from that id.
Any idea how I can fix this? Do I have to force the component to re-update?
Parent component (Card Wrapper)
class CardWrapper extends React.Component {
constructor(props) {
super(props);
this.state = {
stories: []
};
}
componentDidMount() {
axios
.get(API)
// .then(response => console.log(response))
// get our stories array, check it and then change state to contain our stories
.then(data => {
let stories;
if (data.data.stories && data.data.stories) {
if (Array.isArray(data.data.stories)) {
stories = data.data.stories;
} else {
stories = [data.data.stories];
}
} else {
stories = [];
}
this.setState({
stories: stories
});
});
}
render() {
return (
<CardWrapperDiv>
<div className="headingWrapper">
<div className="heading"> Suggested for you</div>
</div>
<Cards>
{this.state.stories.map(story => {
return (
<Card
title={story.content.title}
img={story.content.img}
description={story.content.description}
deadline={story.content.deadline_date}
tags={story.content.tags}
key={story.id}
id={story.id}
/>
);
})}
</Cards>
</CardWrapperDiv>
);
}
}
export default CardWrapper;
Child component
class Card extends React.Component {
render() {
return (
<CardDiv>
<div className="cardbox">
<div className="cardDetails">
<div className="headlineText">
<Link to={`/result/${this.props.id}`}> {this.props.title} </Link>
</div>
<div className="headlineSub">Colombo, Sri Lanka</div>
<div className="headlineDes">{this.props.description}</div>
<div className="textRemain">
{" "}
Deadline date: {this.props.deadline}
</div>
<div className="buttonRow">
<button className="downloadBtn">Download</button>
<button className="viewBtn">View</button>
</div>
</div>
<div className="cardimgwrapper">
<div className="cardimg">
<img src={this.props.img} alt="some title" />
</div>
</div>
</div>
</CardDiv>
);
}
}
export default Card;
Sorry it seems I have figured this out using the following post - Can you force a React component to rerender without calling setState?
Although I'm not exactly sure if it's the best way to go about it.
Essentially I used an OnClick listener to run a function and forces a re-render of the entire component.
Hope this can help someone else :)
class Card extends React.Component {
handleButtonClick() {
this.forceUpdate();
}
render() {
return (
<CardDiv>
<div className="cardbox">
<div className="cardDetails">
<div className="headlineText">
<Link to={`/result/${this.props.id}`} onClick={this.handleButtonClick}> {this.props.title} </Link>
</div>
<div className="headlineSub">Colombo, Sri Lanka</div>
<div className="headlineDes">{this.props.description}</div>
<div className="textRemain">
{" "}
Deadline date: {this.props.deadline}
</div>
<div className="buttonRow">
<button className="downloadBtn">Download</button>
<button className="viewBtn">View</button>
</div>
</div>
<div className="cardimgwrapper">
<div className="cardimg">
<img src={this.props.img} alt="some title" />
</div>
</div>
</div>
</CardDiv>
);
}
}
export default Card;
U have to use ur child component as a pure component. PureComponent Update when ur props change.
class Card extends React.PureComponent {
handleButtonClick() {
this.forceUpdate();
}
render() {
return (
<CardDiv>
.....
.....
</CardDiv>
);
}
}
export default Card;
I am trying to separate my component and container code.
I know the function handleHide() in MainContainer is getting called when the Button "Hide" in Main.js gets pressed because the Alert located in the handleHide() function works.
So basically it's a matter of if opacity cannot be changed through props or I am missing something.
Below is my Main.js file (Component)
import React from 'react'
const styles = {
transition: 'all 1s ease-out'
}
export class Main extends React.Component {
render () {
return (
<div>
<nav>
<div className='nav-wrapper'>
<a href='/' className='brand-logo'>Todays’ EDM</a>
<ul id='nav-mobile' className='right hide-on-med-and-down'>
<li><a href='sass.html'>Music</a></li>
<li><a href='badges.html'>Playlists</a></li>
<li><a href='collapsible.html'>News</a></li>
</ul>
</div>
</nav>
<div className='container'>
<div className='row'>
<div className='s12' />
</div>
<div className='row'>
<div className='s8 offset-s2 center-align'>
<div className='card green accent-4 z-depth-2'
style={{...styles, opacity: this.props.opacity, transform: 'scale(' + this.props.scale + ')'}}>
<div className='card-content white-text'>
<span className='card-title'>Title</span>
</div>
<div className='card-action'>
<a onClick={this.props.hide}>HIDE</a>
</div>
</div>
</div>
</div>
</div>
</div>
)
}
}
This is my MainContainer.js file (Container)
import React from 'react'
import { Main } from '../components/Main'
export class MainContainer extends React.Component {
constructor (props) {
super(props)
this.state = {
opacity: 1,
scale: 1
}
this.handleHide = this.handleHide.bind(this)
this.handleScale = this.handleScale.bind(this)
}
handleHide () {
this.setState({
opacity: 0
})
alert('Goodbye world')
}
handleScale () {
this.setState({
scale: this.state.scale > 1 ? 1 : 1.2
})
}
render () {
let hide = this.handleHide
return (
<Main hide={hide} />
)
}
}
Modify your code in MainContainer.js as below...
<Main hide={hide} {...this.state} />
Below is an example of me editing a "course" object in the database. Works perfectly fine on desktop but not on my iPhone. I'm unable to check on Android or other devices.
Not sure what more detail I could add but I need to since StackOverflow won't let me post until I use this filler. Please ignore this entire paragraph....
imports...
class EditCoursePage extends React.Component {
constructor(props, context) {
super(props, context);
this.state = {
name: this.props.name,
submitted: false,
_creator: {},
};
this.updateName = this.updateName.bind(this);
this.onSubmit = this.onSubmit.bind(this);
this.handleLogout = this.handleLogout.bind(this);
this.handleBack = this.handleBack.bind(this);
}
handleBack(event) {
window.location.href = `/courses/${this.props.match.params.cuid}`;
}
updateName(event) {
var input = event.target.value;
this.setState({
name: input,
});
}
componentWillMount() {
this.props.dispatch(actions.getCourse(this.props.match.params.cuid));
}
componentDidMount() {
this.props.dispatch(actions.getCourse(this.props.match.params.cuid));
}
onSubmit(event) {
const name = this.state.name;
const instructor = cookies.get('instructor')._id;
console.log(cookies.get('instructor')._id);
this.setState({
submitted: true,
});
this.props.dispatch(actions.editCourse(name,this.props.match.params.cuid));
console.log(this.props.name);
console.log(name, cookies.get('instructor')._id);
}
render() {
if (this.state.submitted) {
window.location.href = `https://young-mountain-65748.herokuapp.com/courses/${this.props.match.params.cuid}`;
}
return (
<div className="edit-course-form">
<div className="menu">
<Menu>
<a
id="dashboard-return"
className="menu-item"
href={`/courses/${this.props.match.params.cuid}`}
>
Back to Your Course
</a>
<a id="dashboard-logout" className="menu-item" href="/login">
Logout
</a>
</Menu>
</div>
<div className="mobile-header">
<div className="mobile-name">{this.props.name}</div>
</div>
<div className="edit-course-nav-options">
<div className="course-app-name">School Management App</div>
<ul>
<li>
<Link to="/login" onClick={this.handleLogout}>Log out </Link>
</li>
<li>
<Link to={`/courses/${this.props.match.params.cuid}`}>
Back to Your Course
</Link>
</li>
</ul>
</div>
<div className="container">
<div className="edit-course-name"><h2>{this.props.name}</h2></div>
<div className="submitForm">
<div className="field-line">
<label htmlFor="coursename">New Course Name:</label>
<input
id="coursename"
name="coursename"
value={this.state.name}
onChange={this.updateName}
/>
</div>
</div>
</div>
<div className="edit-course-buttons">
<button className="edit-course" onClick={this.onSubmit}>
Edit Course
</button>
<button className="edit-course-back" onClick={this.handleBack}>
Back
</button>
</div>
</div>
);
}
}
const mapStateToProps = (state, props) => {
return {
name: state.course.course.name,
_creator: state.course._creator,
};
};
export default connect(mapStateToProps)(EditCoursePage);
I am new to react js,I am little confused that how to stop triggering simple button from triggering when user clicks Enter Button ...
Sorry my code will be Awkward ...... If it is Uncomfortable to Read Feel free to comment it out
import React from 'react';
import {connect} from 'react-redux';
import {Link} from 'react-router';
import * as headerAction from '../../Actions/headerActions';
import * as notificationActions from '../../Actions/notificationActions';
import * as tagProfileActions from '../../Actions/tagProfileActions';
class TagProfile extends React.Component{
static contextTypes = {
router:React.PropTypes.object
};
constructor(props){
super(props)
this.state = {
data:[],
tagName:"",
In:null,
tagId:"",
tagFollowers:0,
isFollowStatus:""
}
this.handleFollow =this.handleFollow.bind(this)
}
handleFollow(e){
//How to Prevent this
console.log(e.keyCode)//Udefined
e.preventDefault();
console.log('Clicked')
}
render(){
console.log(this.state)
return (
<div className="ContainerForTagProfile">
<div className="TagProfileTopSecTion">
<h1>Topic: {this.state.tagName} </h1>
</div>
<div className="StatusBarRealTimeViewsAndFollowButtn">
<div className="ViewCcountBar">
<p>30,18,5222 👁 </p>
</div>
<div className="FollowButtonForTagPRofile">
<button type="button" onClick={(e)=>this.handleFollow(e)}>{this.state.tagFollowers} | {this.state.isFollowStatus}</button>
</div>
</div>
<div className="GallerySectionForTagforfile">
{this.state.data.map(data => {
return (
<Link key={data.id} href="#" target="_blank" to={'/'+data.postId}><div className="SingleImagePost">
<img src={data.thumNailUrl} />
<div className="LiveViewCountBar">
<p>{data.views} 👁 - {data.whoLikedIt.length} ❤</p>
</div>
<div className="LikesBar">
<div className="MakeItCenter">
<div className="ProfileTinyImage">
<img src={data.postOwnerPic} />
</div>
<div className="ProfilePosTOwnerName">
<p>{data.postOwnerFullName}</p>
</div>
</div>
</div>
</div></Link>
)
})}
</div>
</div>
)
}
}
const mapStateToProps = (state) => {
return {
isLoggedIn:state.logInStatus
}
};
const mapDispatchToProps = (dispatch) => {
return {
getTagProfileData:(slug) => dispatch(tagProfileActions.getTagDetails(slug)),
getTagFollowInfo:slug => dispatch(tagProfileActions.getTagFollowInfo(slug)),
toogleSignInOut:bool => dispatch(headerAction.toggleSignPop(bool)),
popErrorNotification:(bool,color,message) => dispatch(notificationActions.popUpNotification(bool,color,message)),
tagProfileFollow:(data) => dispatch(tagProfileActions.tagProfileFollow(data))
}
};
export default connect(mapStateToProps,mapDispatchToProps)(TagProfile)
Finally I got Solution
Just added KeyDown and Onclick Evt And Throwed some if else statement for KeyBoard Events..
handleFollow(e){
e.preventDefault()
if(e.type !== 'keydown'){
//Start Code From here
}
}