How to open a form in new tab/window in reactjs - reactjs

i wan to open a form in new window. i am following David Gilbertson
post
to open new window.
i wrote my form here
{this.state.showWindowPortal && (
<MyWindowPortal>
<div>
<input type="file" onChange={this.handleChange} />
<img src={this.state.file}/>
</div>
</MyWindowPortal>
)}
and i wrote this handle change in my main component. but i am able to make a call to this function.
i have two component
class DisplayCard extends React.Component {}
and
class MyWindowPortal extends React.PureComponent {}
i also tried to write this function in MyWindowPortal but still unable to call this function
handleChange=(event)=> {
console.log("in image",event)
this.setState({
file: URL.createObjectURL(event.target.files[0])
})
}
here is the sandbox url for the same.
https://codesandbox.io/s/sad-driscoll-wetlw

Dont know why but adding the following lines to App.js makes it work
componentDidMount() {
window.setInterval(() => this.setState({}), 500);
}
May be The clicks on portal is updating the react state but its not updating the DOM, So, due to that setInterval, it triggers rerender and during that re render its checking the state and unmonting the component.
I cant tell you the exact workaround or why this is happening, will look in to it

Related

this undefined in arrow function

I am creating a component that contains of a Form with a Submit button. In the OnSubmit of the Form I call an arrow function. Inside this function I call the object "this" but I get the error message that it is undefined. However, if I just do a console.log(this) in the OnSubmit of the form instead of calling the arrow function, this is defined. Anyone knows how to solve this issue ? I am actually following a react/ethereum course and even though the code of the instructor works in his video, his code doesn't work when I use it.
import React, {Component} from 'react';
import { Button, Form, Input, Message } from 'semantic-ui-react'
class CampaignNew extends Component{
state = {
minimumContribution: "",
errorMessage: ""
}
onSubmit = async (event) => {
event.preventDefault();
this.setState({errorMessage: "test error"});
}
render(){
return (
<div>
<Form onSubmit={this.onSubmit} error={this.state.errorMessage}>
<Form.Field>
<label>Minimum contribution</label>
<Input
labelPosition="right"
value={this.state.minimumContribution}
onChange={event => this.setState({minimumContribution: event.target.value})}
style={{width: "250px"}} placeholder='0' />
</Form.Field>
<Button type='submit' primary>Create</Button>
</Form>
</div>
)
}
}
export default CampaignNew;
Your code runs fine for me, but there is some missing information on how you are creating your component. It seems you may not be using Create-React-App. Your issue is with method binding in a class component.
The React documentation (https://reactjs.org/docs/handling-events.html) states:
You have to be careful about the meaning of this in JSX callbacks. In JavaScript, class methods are not bound by default. If you forget to bind this.handleClick and pass it to onClick, this will be undefined when the function is actually called.
This is not React-specific behavior; it is a part of how functions work in JavaScript. Generally, if you refer to a method without () after it, such as onClick={this.handleClick}, you should bind that method.
If calling bind annoys you, there are two ways you can get around this. If you are using the experimental public class fields syntax, you can use class fields to correctly bind callbacks:
class LoggingButton extends React.Component {
// This syntax ensures `this` is bound within handleClick.
// Warning: this is *experimental* syntax.
handleClick = () => { console.log('this is:', this); }
render() {
return (
<button onClick={this.handleClick}>
Click me
</button>
);
}
}
This syntax is enabled by default in Create React App.
Also the error prop of the Form component should be a boolean and the async word is not required in the code you provided.
That's related to how this value is defined in javaScript. You should know that "this" value is defined by who calls it in runtime.
In Class, "this" value is the same this value of its parent. In this code, "this" value is CampaignNew class object.
class CampaignNew extends Component{
onSubmit = async (event) => {
event.preventDefault();
this.setState({errorMessage: "test error"});
}
But "this" value is different in code below.
<Form onSubmit={this.onSubmit}
This is because Form element calls onSubmit which means this value in onSubmit is the same value of Form element's "this" and Form element doesn't have this value so this is why the value's undefined.
I found the problem. It was my version of NextJS. If I downgrade it to an earlier version, everything works fine. No idea why it breaks in the new version.
Working version: "next": "^11.1.3"

Form input state doesn't show update in developer tools, but logs them. Am I rerendering properly?

I am learning about Controlled Forms, and have built a simple one input form, to practice on. It seems that the state of the component is not being updated, when I look at my react developer tools. If I console.log the state, I can see the state has changed with each letter I input, but nothing is changing in the developer tool. I am concerned it may not be rendering properly.
I've built the form, exported and imported into App.js. Everything seems to be wired correctly, including a console.log to display the state with each change.
class Form extends Component {
constructor(props) {
super(props);
this.state = {
username: ''
}
this.handleChange = this.handleChange.bind(this)
}
handleChange(evt) {
this.setState(
{username: evt.target.value},
() => console.log(this.state)
)
}
render() {
return (
<form>
<input
name="username"
value={this.state.username}
onChange={this.handleChange}
/>
</form>
)
}
}
I don't get any errors, but observed 2 interesting things: in react-developer-tools, under the form component, the state stays the same, but a little arrow pops up that says "reset value," and if I click on the App component, then back on the Form, the state is filled with the value.
You can check the React documentation:
The second parameter to setState() is an optional callback function that will be executed once setState is completed and the component is re-rendered. Generally we recommend using componentDidUpdate() for such logic instead.
So everything is working as expected, if the callback is getting called it's because the component re-rendered.
Are you using the latest version of react developer tools released last month?

How to re render a static component in reactjs

I am developing a webapp in reactjs using typescrpit in visual studio 2017, which is very new technology for me. I am stuck at a problem where i dont know how to re-render a component from another component.
I have a log in page. What i want to do is display the username in my header component when the user logs in. Only problem is, the header component is common for all my web pages. Following is my layout.tsx file:-
export interface LayoutProps {
children?: React.ReactNode;
}
export class Layout extends React.Component<LayoutProps, {}> {
public render() {
return <div>
<Header />
<div className='layout_wrapper'>
{this.props.children}
</div>
<Footer />
</div>;
}
}
This is the only file where i have used my header component so that i wont have to use it in every component i create. componentDidMount() of header component will check for access token and make an api call to get user details. Now my question is, how can i re-render this component from another component so that when the user logs in, he can see his name in this header component? Please tell me if i need to provide more code if my question is not clear. Thanks
Considering this is a small app, this solution will work. But it shouldn't be used when the app isn't a small one, because it will make the code complex.
So, according to information given by you, the hierarchy is as follows:
<Header>
<SignIn>
<SignInContent/>
</SignIn>
</Header>
,where SignInContent component is calling the api. We will define a function in Header, and pass it as props to the SignIn component
export class Header extends React.Component<HeaderProps, HeaderState> {
constructor(){
this.state = { isLoggedIn: false }; //Add this to existing state variables
}
render() {
return {
<SignIn setIsLoggedInTrue={this.setIsLoggedInTrue.bind(this)} />
}
}
componentDidUpdate(prevProps, prevState) {
if(this.state.isLoggedIn && !prevState.isLoggedIn) {
// Make the api call for fetching user details
}
}
setIsLoggedInTrue() {
this.setState({isLoggedIn: true});
}
}
And in the SignIn component, again in the render method pass the props to SignInContent like this:
<SignInContent setIsLoggedInTrue={this.props.setIsLoggedInTrue} />
once it is logged in, you can call this.props.setIsLoggedInTrue function from the SignInContent component. This should solve your purpose
Your component will be re-rendered if the supplied props have changed.
By looking at your code, the value of this.props.children should change which will eventually trigger a re-render of your component
Also, if you want to know how to trigger it at login. There should be a componentWillReceiveProps method which checks the login state of the user, and if found logged in will update the values passed to the component :)
EDIT
Here's a sample code to your problem. Since this.props.children is used. You'll need to use it like this.
render() { return (
<Layout>
{this.state.userName}
</Layout>
);}
Now call the api and set the userName

Render called on every setState when using touch gestures

I have a problem using touch gestures in my react.js app. The problem is that the render() function is called on every setState call and not just at the end. This only happens when using Hammer.js to handle the tap. If using a regular button the render() function is only called once.
A few things to note:
I have also tried using react-hammerjs and ZingTouch with exactly the same result.
In the example i just use the Tap "gesture" but the result is the same if using for example the Swipe gesture.
I tried to use MobX for state instead. But again with the same result.
Here is my example that I have tried to make as simple as possible (the example does not make sense, but illustrates the problem):
import React from 'react';
import ReactDOM from 'react-dom';
import Hammer from 'hammerjs';
class Game extends React.Component {
constructor(props) {
super(props);
this.state = { value: 1 };
}
action() {
console.log(1)
this.setState({ value: 1 });
console.log(2)
this.setState({ value: 2 });
console.log(3)
this.setState({ value: 3 });
console.log(4)
this.setState({ value: 4 });
console.log(5)
}
componentDidMount() {
this.hammer = Hammer(this._touchdiv);
this.hammer.on('tap', () => this.action());
}
componentWillUnmount() {
this.hammer.off('tap', this.action)
}
render() {
console.log('Render');
return (
<div>
{this.state.value}
<div ref={(el) => this._touchdiv = el}> Touch div</div>
<button onClick={() => this.action()} value='update' >Normal button</button>
</div>
);
}
}
ReactDOM.render(<Game />, document.getElementById('root'));
The console output when using the regular button:
1
2
3
4
5
Render
The console output when using the "touch div":
1
Render
2
Render
3
Render
4
Render
5
I have tried to google it but could not find any similar examples.
Any idea what is happening? Any possible solution is welcome.
Edit 1:
ReyHaynes suggested that the ref could be the problem. I tried to change
<div ref={(el) => this._touchdiv = el}> Touch div</div>
to
<div className='xxx'> Touch div</div>
and changed
this.hammer = Hammer(this._touchdiv);
to
this.hammer = Hammer(document.getElementsByClassName("xxx")[0]);
The result is exactly the same. Yes, this is dirty code but it illustrates that the problem exists without using refs.
When using refs, once state changes, you re-render all the components of your UI that depend on that state.
React will take care of making sure only the right bits of the DOM is updated, making the whole thing efficient but render is called to check for the necessary changes.
Here's the docs on that: https://reactjs.org/docs/refs-and-the-dom.html
So essentially, this part of the touch code causes the render() to run:
ref={(el) => this._touchdiv = el}
Checking the call stack it seems like it's different how the callback is triggered.
Hammer will just call the callback if the gesture is recognized.
React catches the click event and sets the flag 'isBatchingUpdates' to true, making the render to wait until all setState are done.
Edit:
Found this article explaning it: https://itnext.io/react-setstate-usage-and-gotchas-ac10b4e03d60
"Currently (React 16 and earlier), only updates inside React event handlers are batched by default."

how to Trigger componentWillReceiveProps on React-storybook

I am trying to test my UI component on React Storybook (link). However, I will like to add a button so when I pressed it, it will pass a new props to the component that is already rendered, (hence trigger the lifecycle method componentWillReceiveProps). However, I don't know how to do that. I will really appreciate any helps on this, thank you.
You need to find the first shared parent of the button and the component that you're trying to trigger componentWillReceiveProps for.
For instance, suppose your structure looks like this:
<SomeComponent>
<AnotherComponent someProp={someValue} />
<AThirdComponent>
<button />
</AThirdComponent>
</SomeComponent>
SomeComponent is the first shared parent of AnotherComponent and the button.
Once you've found your shared parent, add some state and a method to it:
class SomeComponent extends React.Component {
constructor(props) {
super(props);
this.updateButton = this.updateButton.bind(this);
this.state = { buttonWasClicked: false };
}
updateButton() {
this.setState({ buttonWasClicked: true});
}
}
Now pass the updateButton method down to your button in AThirdComponent and attach the state to AnotherComponent:
render() { // SomeComponent's render method
return (
<div>
<AnotherComponent buttonWasClicked={this.state.buttonWasClicked} />
<AThirdComponent updateButton={this.updateButton}`/>
</div>
);
}
And in AThirdComponent, attach the updateButton handler to the button:
<button onClick={this.props.updateButton} />
Now when you click the button, SomeComponent's state will update, causing it to pass new props to AnotherComponent.

Resources