I'm currently working on a react application. I've a top bar with button and I want to render Registration component to the onClick function. There's no output with the below, I'm I missing something here?
'use strict'
import React from 'react'
import Registration from 'Registration'
export default class Header extends React.Component {
constructor (props) {
super (props)
this.handleClick = this.handleClick.bind(this)
}
handleClick () {
<Registration />
}
render () {
return (
<div className='top-bar'>
<div className='top-bar-left'>
<ul className='menu'>
<li className='menu-text'>SIS App</li>
<li>
<button className='button' type='button' onClick={this.handleClick}>Create Info</button>
</li>
</ul>
</div>
</div
)
}
}
Here is my Registration component:
'use strict'
import React, {Component} from 'react'
export default class Registration extends Component {
render () {
let props = this.props
let {edit} = props
let handleChange = props.handleChange()
return (
<fieldset>
<legend>Registration</legend>
<input name='name'
value={props['name']}
type='text'
placeholder='Your Name'
onChange={handleChange}
/>
<input name='email'
value={props['email']}
type='email'
placeholder='Email'
onChange={handleChange}
/>
<input name='phone'
value={props['phone']}
type='tel'
pattern={PhoneNumberPattern}
placeholder='Phone'
onChange={handleChange}
/>
</fieldset>
)
}
}
And my app.js:
'use strict'
import React from 'react'
import { render } from 'react-dom'
import Header from 'Header'
render(
<div>
<Header />
</div>,
document.getElementById('app')
)
You want to render the registration component, but you are not defining any place for it to render,
import React from 'react'
import Registration from 'Registration'
export default class Header extends React.Component {
constructor (props) {
super (props)
this.state = {
registration: false
}
this.handleClick = this.handleClick.bind(this)
}
handleClick () {
this.setState({registration: true})
}
render () {
return (
<div className='top-bar'>
<div className='top-bar-left'>
<ul className='menu'>
<li className='menu-text'>SIS App</li>
<li>
<button className='button' type='button' onClick={this.handleClick}>Create Info</button>
<li>
</ul>
{this.state.registration ? <Registration/>: null}
</div>
)
}
}
However I suppose ideally you would want to route to your registration component whenever the button is click, your could do that using dynamic routing after defining a route for your registration component.
Refer this solution, if you wish to do it this way
In handleClick you can change state like this this.setState({ renderRegistration: true }) and then in render function do the following
if (this.state.renderRegistration) {
return '<Registration />';
} else {
// your existing code
}
You have to correct two things, firstly you have to import Header correctly in main.js, as follows:
main.js
'use strict'
import React from 'react'
import { render } from 'react-dom'
import Header from './Header.jsx'
render(
<div>
<Header />
</div>,
document.getElementById('app')
)
Secondly, define and bind handleChange function you are using in Registration component and provide the area to render the same, a follows:
Header.jsx
'use strict'
import React from 'react'
import Registration from './Registration.jsx'
export default class Header extends React.Component {
constructor (props) {
super (props)
this.state = { showRegistration: false }
this.handleClick = this.handleClick.bind(this)
this.handleChange = this.handleChange.bind(this)
}
handleClick(e) {
this.setState({ showRegistration: true })
console.log("The link was clicked");
}
handleChange(e) {
console.log("handleChange was clicked");
}
render () {
let registration = null;
if (this.state.showRegistration) {
registration = <Registration handleChange = {() => this.handleChange()}/>
}
return (
<div className='top-bar'>
<div className='top-bar-left'>
<ul className='menu'>
<li className='menu-text'>SIS App</li>
<li>
<button className='button' type='button' onClick={this.handleClick}>Create Info</button>
</li>
</ul>
</div>
{registration}
</div>
)
}
}
Considering the layout of app, as below:
The only thing that your Header component will render to the screen is what's in the render function.
One approach here is to have a flag that controls whether to display the Registration component, which is controlled by the button click event.
I don't know where your registration component needs to go, but try something like this:
'use strict'
import React from 'react'
import Registration from 'Registration'
export default class Header extends React.Component {
constructor (props) {
super (props)
this.state = { showRegistration: false }
this.handleClick = this.handleClick.bind(this)
}
handleClick () {
this.setState({ showRegistration: true })
}
render () {
return (
<div className='top-bar'>
<div className='top-bar-left'>
<ul className='menu'>
<li className='menu-text'>SIS App</li>
<li>
<button className='button' type='button' onClick={this.handleClick}>Create Info</button>
<li>
</ul>
</div>
{this.state.showRegistration && <Registration />}
</div>
)
}
}
Related
I have a form that submit some data and i have item component that has a delete button that delete an item but when i submit something it submit and delete the item in the same time
import React, {Component} from 'react';
import ApiClient from './apiClient';
import './MessageForm.css';
class MessageForm extends Component {
constructor(props){
super(props);
this.state = {
submitted: false
}
}
handleSubmit = async (event) => {
event.preventDefault();
const messageData = new FormData(event.target);
await ApiClient.addMessage({
license_plate: messageData.get('license'),
body: messageData.get('body')
});
// console.log("submitted");
// this.props.refreshList();
};
render() {
return(
<form onSubmit={this.handleSubmit} className="MessageForm">
<div>
<label htmlFor="license">License Plate</label>
<input id="license" name="license" type="text" />
</div>
<div>
<label htmlFor="body">Message</label>
<textarea id="body" name="body" type="text"/>
</div>
<div>
<input type="submit" value="Submit"/>
</div>
</form>
)
}
};
export default MessageForm;
this is the item component
import React from 'react';
import moment from 'moment';
import SocailShare from './SocialShare.css'
import { FacebookShareButton, LinkedinShareButton,
TwitterShareButton,
TelegramShareButton,
WhatsappShareButton,
EmailShareButton,} from 'react-share';
import { FacebookIcon, EmailIcon,
TwitterIcon,
TelegramIcon,
WhatsappIcon,
LinkedinIcon,} from 'react-share';
import {
FacebookShareCount,
PinterestShareCount,
VKShareCount,
OKShareCount,
RedditShareCount,
TumblrShareCount,
} from 'react-share';
import './MessageItem.css';
export default ({ id, submission_date, license_plate, body, handleDelete }) => {
var timePosted = moment(submission_date).format('DD/MM/YYYY - HH:mm');
const onDelete = (id) => {
handleDelete(id);
}
return (
<li className="MessageItem">
<span>Time: {timePosted} - </span>
<span>To license: {license_plate} : </span>
<span> {body} </span>
<button onClick={onDelete(id)}>X</button>
<div className="SocialShare">
<FacebookShareButton url="https://github.com/nygardk/react-share#readme" >
<FacebookIcon size={30}/>
<FacebookShareCount url="https://github.com/nygardk/react-share#readme">
{shareCount => (
<span className="myShareCountWrapper">{shareCount}</span>
)}
</FacebookShareCount>
</FacebookShareButton>
<TwitterShareButton url="https://github.com/nygardk/react-share#readme">
<TwitterIcon size={30}/>
</TwitterShareButton >
<EmailShareButton url="https://github.com/nygardk/react-share#readme">
<EmailIcon size={30}/>
</EmailShareButton>
</div>
</li>
);
};
and this is the message list component that renders the message item
import React, { Component } from 'react';
import './MessageList.css';
import MessageItem from './MessageItem';
import ApiClient from './apiClient'
class MessageList extends Component {
constructor(props) {
super(props);
}
handleOnDelete = async (id) => {
console.log(id + "deleted")
await ApiClient.deleteMessage(id);
this.props.refreshList();
}
render() {
const {
messages
} = this.props;
messages.sort(function(a,b){
//the list will be ordered in descending date order (most recent first)
return new Date(b.submission_date) - new Date(a.submission_date);
});
const $messages = messages.map((message) => <MessageItem handleDelete={this.handleOnDelete} key={message._id} {...message} />);
return (
<section className="MessageList">
<h1>Message Board</h1>
<ul>
{$messages}
</ul>
</section>
)
}
}
export default MessageList;
and this is the app component where everything is rendered
import React, { Component} from 'react';
import {BrowserRouter, Route, Switch} from 'react-router-dom';
import ApiClient from './apiClient';
import './App.css';
import MessageForm from './MessageForm';
import MessageList from './MessageList';
class App extends Component {
constructor(props){
super(props);
this.state = {
messages: []
}
}
componentDidMount = async () => {
this.refreshList();
}
refreshList = async () => {
const messages = await ApiClient.getMessages();
this.setState({
messages
})
}
render () {
return (
<BrowserRouter>
<div className="App">
<header className="App-header">
<h1>Hello License</h1>
<p>Send your messages to a plate number easily!</p>
</header>
<MessageForm refreshList = {this.refreshList}/>
</div>
<Switch>
<Route exact path="/api" render ={props => <MessageList refreshList = {this.refreshList} messages={this.state.messages} {...props}/> }/>
</Switch>
</BrowserRouter>
)
}
};
export default App;
in your item component, this line <button onClick={onDelete(id)}>X</button> is your problem.
What you are inadvertently saying is that when the DOM renders this component, it should call onDelete right away, and the onClick handler will refer to void. To avoid this, what you want is to pass in a function like so: <button onClick={(id) => onDelete(id)}>X</button>
I am trying to concat the data entered in text field passing data from another stateless component, using props. Not sure why it is not working.
I have created two components
app.js 2. title.js
Data entered in input field needs to concat the string every time and display dynamically using props.
App.js
import React, { Component } from 'react';
import logo from './logo.svg';
import './App.css';
import Home from './Home';
import Title from './Title';
class App extends Component {
constructor(props)
{
super(props);
this.state =
{
text : ' ',
collection: []
}
this.eventHandler = this.eventHandler.bind(this);
this.eventSubmit = this.eventSubmit.bind(this);
}
eventHandler(event)
{
this.setState(
{text:event.target.value}
)
}
eventSubmit(event)
{
this.setState(
{collection:this.state.collection.concat(this.state.text)}
)
}
render() {
return (
<div className="App">
<input type="text" onChange ={this.eventHandler} />
<p> {this.state.text} </p>
<input type="submit" onClick={this.eventSubmit} />
<title collection={this.state.collection} />
</div>
);
}
}
export default App;
Title.js
import React from 'react';
const title = (props) =>
{
return (
<div>
<h1> {this.props.collection.toString()} </h1>
<h1> hello </h1>
</div>
);
}
export default title;
setState is async and when you use this.state inside it, it might not re-render. Use function inside setState instead:
eventSubmit(event) {
this.setState((prevState, props) => ({
collection: prevState.collection.concat(prevState.text)
}));
}
See 3. setState() is async: https://codeburst.io/how-to-not-react-common-anti-patterns-and-gotchas-in-react-40141fe0dcd
Mutations are bad in general and can lead to side effects use spread operator(...) to copy prevState array instead.
eventSubmit(event) {
this.setState((prevState) => ({
collection: [...prevState.collection, prevState.text]
}));
}
That's how you append data in array and update the state
Instead of stateless component I have created class component and it worked. Can someone explain me why it didn't worked with stateless why it worked now.
App.js
<code>
import React, { Component } from 'react';
import logo from './logo.svg';
import './App.css';
import Home from './Home';
import Title from './Title';
import Collection from './Collection';
class App extends React.Component {
constructor(props)
{
super(props);
this.state =
{
text : ' ',
collection: []
}
this.eventHandler = this.eventHandler.bind(this);
this.eventSubmit = this.eventSubmit.bind(this);
}
eventHandler(event)
{
this.setState(
{text:event.target.value}
)
}
eventSubmit(event)
{
this.setState(
{collection:this.state.collection.concat(this.state.text)}
)
}
render() {
return (
<div className="App">
<h1> ramesh </h1>
<input type="text" onChange ={this.eventHandler} />
<p> {this.state.text} </p>
<input type="submit" onClick={this.eventSubmit} />
<title name ={this.state.collection} />
<Collection name={this.state.collection} />
</div>
);
}
}
export default App;
</code>
Collection.js
<code>
import React, {Component} from 'react';
class Collection extends React.Component
{
render()
{
return(
<div>
<h1> {this.props.name.toString()} </h1>
</div>
);
}
}
export default Collection;
</code>
i want to change state different js but i can not , i have a sidebar.js with react-burger-menu
i want to call and change toggleMenu state in header.js
When I click the menu link, i want to toggle react-burger-menu but different js. this is not working.
sidebar.js
import React from "react";
import PropTypes from "prop-types";
import { reveal as Menu } from "react-burger-menu";
import * as FontAwesome from "react-icons/lib/fa";
export default class SidebarMenu extends React.Component {
constructor (props) {
super(props)
this.state = {
menuOpen: false
}
}
handleStateChange (state) {
this.setState({menuOpen: state.isOpen})
}
closeMenu () {
this.setState({menuOpen: false})
}
toggleMenu () {
this.setState({menuOpen: !this.state.menuOpen})
}
render () {
return (
<div>
<Menu
isOpen={this.state.menuOpen}
onStateChange={(state) => this.handleStateChange(state)}
>
// menu content
</Menu>
</div>
</div>
)
}
}
header.js have link for react-burger-menu
import React from 'react';
import PropTypes from 'prop-types';
import SidebarMenu from "../SidebarMenu";
export default class Header_Video extends React.Component {
render() {
return (
<Container>
<Row>
<Col md={5} sm={12} xs={12} className="text-left mobile-right">
<div className="bar__module">
<a onClick={this.toggleMenu}>Menu</a>
</div>
</Col>
</Row>
</Container>
);
}
}
thanks for help
note: i have a app.js all files import. I want to run toggleMenu in header.js
app.js
const TemplateWrapper = ({ children }) => (
<div id="outer-container">
<SidebarMenu />
<main id="page-wrap" className="page-wrap">
<HeaderVideo /> {children()}
<Footer />
</main>
</div>
);
menuOpen should be in a parent state of both components.
Example:
class App extends React.Component {
constructor (props) {
super(props)
this.state = {
menuOpen: false
}
}
closeMenu = () => {
this.setState({menuOpen: false})
}
toggleMenu = () => {
this.setState({menuOpen: !this.state.menuOpen})
}
render() {
return (
<div>
<SidebarMenu isMenuOpen={this.state.menuOpen} toggleMenu={this.toggleMenu} />
<Header toggleMenu={this.toggleMenu} />
</div>
)
}
}
You may have further errors beyond just this, but the glaring error to me is that toggleMenu() is not bound to the constructor.
https://reactjs.org/docs/handling-events.html
try:
import React from "react";
import PropTypes from "prop-types";
import { reveal as Menu } from "react-burger-menu";
import * as FontAwesome from "react-icons/lib/fa";
export default class SidebarMenu extends React.Component {
constructor (props) {
super(props)
this.state = {
menuOpen: false
}
this.toggleMenu = this.toggleMenu.bind(this);
// the above statement binds the function to the object constructor
}
handleStateChange (state) {
this.setState({menuOpen: state.isOpen})
}
closeMenu () {
this.setState({menuOpen: false})
}
toggleMenu () {
this.setState({menuOpen: !this.state.menuOpen})
}
render () {
return (
<div>
<Menu
isOpen={this.state.menuOpen}
onStateChange={(state) => this.handleStateChange(state)}
>
// menu content
</Menu>
</div>
</div>
)
}
}
You'll also want to use an HTML5 button tag instead of a link tag, the correct HTML semantic structure provides a bunch of underlying features and greatly improves accessibility out of the box.
Also, remove the arrow function and pass a reference to the function, not the returned value. This is so react doesn't call the function immediately but stores the function reference to execute upon the click event.
<button onClick={this.toggleMenu}>Menu</button>
// instead of
<a onClick={() => this.toggleMenu()}>Menu</a>
Hope this helps!
When I compile my files and run in console log I get this error
enter code here
Uncaught TypeError: Cannot read property 'nameOfCity' of null at App.render
They all "meet" at App component(I am using 'create-react-app' pack from facebook). I presume that it should load first Form Container and in it logic set initial state to empty and then Weather info data comes. Or am I wrong?
import React, { Component } from 'react';
import logo from './logo.svg';
import './App.css';
import {FormContainer} from './containers/FormContainer';
import WeatherInfo from './components/WeatherInfo';
class App extends Component {
render() {
return (
<div className="App">
<div className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<h2>Weather App</h2>
</div>
<p className="App-intro">
To get started, edit <code>src/App.js</code> and save to reload.
</p>
<FormContainer label="Name of the city:"/>
<WeatherInfo
nameOfCity={this.state.nameOfCity}
weatherDescription={this.state.weatherDescription}
windSpeed={this.state.windSpeed}
temperature={this.state.temperature}
maxTemperature={this.state.maxTemperature}
minTemperature={this.state.minTemperature}
/>
</div>
);
}
}
export default App;
Form Container
import React, {Component} from 'react';
import SearchBar from '../components/SearchBar';
class FormContainer extends Component {
constructor(props) {
super(props);
this.state = {
cityName: '',
nameOfCity:'',
weatherDescription:'',
windSpeed:'',
temperature:'',
maxTemperature:'',
minTemperature:''
};
this.handleFormSubmit = this.handleFormSubmit.bind(this);
this.handleCityName = this.handleCityName.bind(this);
}
handleFormSubmit(e) {
e.preventDefault();
const SendForm = {
cityName: this.state.cityName
};
console.log(SendForm);
fetch(`http://api.openweathermap.org/data/2.5/forecast/weather?q=${SendForm.cityName}&units=metric&APPID=********`)
.then(res => res.json())
.then(results => {
this.setState({
nameOfCity: results.city.name,
weatherDescription: results.list[0].weather[0].description,
windSpeed: results.list[2].wind.speed,
temperature: results.list[0].main.temp,
maxTemperature: results.list[0].main.temp_max,
minTemperature: results.list[0].main.temp_min
});
});
}
handleCityName(value) {
this.setState({ cityName: value });
}
render() {
return (
<div>
<form onSubmit={this.handleFormSubmit}>
<label>{this.props.label}</label>
<SearchBar
name="CityName"
type="text"
value={this.state.cityName}
placeholder="search"
onChange={this.handleCityName}
/>
<button type="submit"
className=""
value='Submit'
placeholder="Search" />
</form>
</div>
);
}
}
export {FormContainer};
Search bar component
import React, {Component} from 'react';
const SearchBar = (props) => (
<div>
<label>{props.label}</label>
<input name={props.name} type={props.inputType} value={props.value} placeholder={props.placeholder} onChange={(e)=>props.onChange(e.target.value)}/>
</div>
);
export default SearchBar;
and Weather Info component
import React, {Component} from 'react';
const WeatherInfo = (props) => (
<div>
<ul>
<li>{props.nameOfCity}</li>
<li>{props.weatherDescription}</li>
<li>{props.windSpeed}</li>
<li>{props.temperature}</li>
<li>{props.maxTemperature}</li>
<li>{props.minTemperature}</li>
</ul>
</div>
);
export default WeatherInfo;
You're trying to read nameOfCity from this.state in App, but your App component does not hold state.
You can have FormContainer use context and render WeatherInfo as a child:
class FormContainer extends Component {
...
static childContextTypes = {
nameOfCity: React.PropTypes.string
}
getChildContext() {
return {
nameOfCity: this.state.nameOfCity
}
}
render: () {
...
</form>
{this.children}
}
}
App.jsx:
<FormContainer label="Name of the City:">
<WeatherInfo />
</FormContainer>
WeatherInfo.jsx:
class WeatherInfo extends React.Component {
static contextTypes = {
nameOfCity: React.PropTypes.string
}
render: () {
<div>
<ul>
<li>{this.context.nameOfCity}</li>
...
}
}
OR you can store state in App, and have FormContainer change App.state either by passing a prop, or by using context.
The error is occurring at <WeatherInfo nameOfCity={this.state.nameOfCity} because at this point you don't have nameOfCity in the App component state.
In your code, the nameOfCity variable is inside FormContainer component state. If you want to use it across the components, you should have the state at the App component.
Issue is u r using this.state in App component, and in App component u didn't define any state, that's why it is throwing the error, can't read Cannot read property 'nameOfCity' of null, because state is null. U need to define state in App component and then pass this state values in props and use those values in other component.
These type of error occurs when you try to use attributes of non existing data. In this case this.state don't have value i.e. its null. So make sure your this.state have desired value by some manipulation as per your functionality.
Currently, I'm making a modal system with React.
So I have a button in a sidebar and my modal is a div in the body.
I have two component that are rendered in the render function of the main component of my app:
MyModal
MyModalOpenButton
Here is what I need:
When the event onClick of the MyModalOpenButton is triggered, I need to execute a function stored in the MyModal component.
So I basically need to store the ref of MyModal in a var.
How can I do this ?
Codes:
import * as ReactDOM from "react-dom";
import * as React from "react";
import { MyModal } from "./component/modal/my-modal";
import { SettingsButtons } from "./component/settings-buttons";
import { CustomComponent } from "./custom-component";
class App extends CustomComponent<{}, {}>{
constructor() {
super();
}
render() {
return (
<div>
<div className="sidebar">
<ul>
<li>
1
</li>
<li>
2
</li>
<li>
3
</li>
</ul>
<SettingsButtons />
</div>
<div className="mainContent">
</div>
<footer>TODO</footer>
<MyModal />
</div>
);
}
}
const app: App = ReactDOM.render(<App />, document.querySelector("#root")) as App;
And
import * as ReactDOM from "react-dom";
import * as React from "react";
import { CustomComponent } from "./../../custom-component";
import { ButtonComponent } from "./button";
export class MyModalOpenButton extends ButtonComponent<{}, {}> {
constructor() {
super();
}
render() {
return (
<li id="open-button" onClick={this.onClick}>
<i className="fa fa-plus" aria-hidden="true"></i>
</li>
);
}
onClick(event: React.MouseEvent<HTMLElement>) {
// Should open the modal
}
}
You haven't shared your code, so I can't give you an answer that will match your case specifically, but in general:
class MyModal extends React.Component<any, any> {
public render() {
...
}
public onButtonClick() {
...
}
}
interface MyModalOpenButtonProps {
onClick: () => void;
}
class MyModalOpenButton extends React.Component<MyModalOpenButtonProps, any> {
public render() {
return <button onClick={ this.props.onClick } />
}
}
class Main extends React.Component<any, any> {
private myModal: MyModal;
public render() {
return (
<div>
<MyModalOpenButton onClick={ this.onButtonClick.bind(this) } />
<MyModal ref={ modal => this.myModal = modal } />
</div>
);
}
private onButtonClick() {
this.myModal.onButtonClick();
}
}