'State' is not defined and 'handleToggle' is not defined no-undef - javascript

Line 11:5: 'state' is not defined no-undef
Line 15:5: 'handleToggle' is not defined no-undef
I don't understand why it shows me these errors, please help me resolve this, I would also appreciate an explanation
const Footer = () => {
state = {
langContent: false
}
handleToggle = (e) => {
e.preventDefault();
this.setState({
langContent: !this.state.langContent
})
}
return (
<FooterContainer>
<span style={{ marginLeft: '15%', fontSize: '1.125rem' }}>
Questions?
<Link> Call 1-877-742-1335</Link>
</span>
{/* Language Button */}
<div className= "lang-btn" onClick={this.handleToggle}>
<Icon icon={iosWorld} size={20}/>
English
<Icon icon={arrowSortedDown} />
</div>
{/* Toggle Language Content */}
{this.state.langContent && (
<div className="lang-toggle">
<ul>
<li>English</li>
</ul>
<ul>
<li>Hindi</li>
</ul>
</div>
)}
<span style={{ marginLeft: '15%', fontSize: '0.9rem'}}>
Netflix India
</span>
</FooterContainer>
)
}

I think you are confusing the syntax for using state in functional components with the syntax for using states in class components.
To use state in functional components, use it like this: (also you forgot to declare const before the function handleToggle, here you are declaring a function local variable thus const is needed. You are confusing it with declaring a method in a class)
const Footer = () => {
const [state, setState] = useState({ langContent: false })
const handleToggle = (e: { preventDefault: () => void; }) => {
e.preventDefault();
setState({
langContent: state.langContent
})
}
return (
<FooterContainer>
<span style={{ marginLeft: '15%', fontSize: '1.125rem' }}>
Questions?
<Link> Call 1-877-742-1335</Link>
</span>
{/* Language Button */}
<div className= "lang-btn" onClick={this.handleToggle}>
<Icon icon={iosWorld} size={20}/>
English
<Icon icon={arrowSortedDown} />
</div>
{/* Toggle Language Content */}
{state.langContent && (
<div className="lang-toggle">
<ul>
<li>English</li>
</ul>
<ul>
<li>Hindi</li>
</ul>
</div>
)}
<span style={{ marginLeft: '15%', fontSize: '0.9rem'}}>
Netflix India
</span>
</FooterContainer>
)}
If you want to use functional component style, read more about it here: React docs-Using the state hook

The component has been created as a functional component, which does not have state, to fix this issue you can use the useState hook.
const Footer = () => {
const [langContent, setLangContent] = useState(false)
const handleToggle = (e) => {
e.preventDefault();
setLangContent(!langContent);
}
return (
... // Use existing Code
)
}
If you want to continue to using class based components then you should use a class that extends React.Component
class Footer extends React.Component {
constructor(props) {
super(props);
this.state = {
langContent: false
};
}
render() {
... //Use existing Code
}
Additional Reading:
React Docs for hooks-state

Related

How to update a component based on changes in another component in React

There are two components which don't have parent-child or sibling relationship between them.
One of them build the Toolbar and another one contains a color picker. The idea is to change the color of the Toolbar based on the value set in the color picker.
Here is my code so far:
import React from 'react';
import { Button, Icon } from 'semantic-ui-react';
import { ChromePicker } from 'react-color';
export default class Banner extends React.PureComponent {
constructor(props) {
super(props);
this.state = {
displayColorPicker: false,
background: '#fff',
};
}
handleClick = () => {
this.setState({ displayColorPicker: true });
};
handleClose = () => {
this.setState({ displayColorPicker: false });
};
handleChange = color => {
this.setState({ background: color.hex });
};
handleChangeComplete = color => {
this.setState({ background: color.hex });
};
render() {
const popover = {
position: 'absolute',
zIndex: '2',
};
const cover = {
position: 'fixed',
top: '0px',
right: '0px',
bottom: '0px',
left: '0px',
};
return (
<div className="banner-container settings-banner">
<table className="settings-banner-container">
<tbody>
<tr className="setttings-container-tr">
<div
className="xx"
style={{ backgroundColor: this.state.background }}>
<div className="title-cell-value settings-banner-title">
Brand color
</div>
<div>
<Button onClick={this.handleClick}>Pick Color</Button>
{this.state.displayColorPicker ? (
<div style={popover}>
<div
style={cover}
onClick={this.handleClose}
onKeyDown={this.handleClick}
role="button"
tabIndex="0"
aria-label="Save"
/>
<ChromePicker
color={this.state.background}
onChange={this.handleChange}
onChangeComplete={this.handleChangeComplete}
/>
</div>
) : null}
</div>
</div>
</tr>
</tbody>
</table>
</div>
);
}
}
In the above file, the ChromePicker is used to choose a color and save its value in this.state.background. I'm using that value to update the color of div with class xx. This works good, the div's color is updated directly.
However, I don't know how to "export" that color value outside and use it in another component.
In this case it would be the Toolbar, I want to send the value from this.state.background to the style = {{ .. }}
Is there a way to do it?
import React from 'react';
import Logo from '../Logo/Logo';
export default class Toolbar extends React.PureComponent {
render() {
return (
<div className="corporate-toolbar" style={{ backgroundColor: 'green' }}>
<Logo corporate />
</div>
);
}
}
There is many ways to do it
You can use context(best solution), redux(if you app is really big) or just move the property to the common parent and pass it to components (it's the worst way, not recommended)
Documentation for context - https://reactjs.org/docs/context.html
Documentation for redux - https://react-redux.js.org
A simple example of using context https://www.digitalocean.com/community/tutorials/react-usecontext
Here is a working example using context:
//in file ColorContext.js (should export but breaks snippet)
const ColorContext = React.createContext();
const ColorProvider = ({ children }) => {
const [color, setColor] = React.useState('#fff');
return (
<ColorContext.Provider value={{ color, setColor }}>
{children}
</ColorContext.Provider>
);
};
//in file Banner.js
class Banner extends React.PureComponent {
handleChange = (color) => {
this.context.setColor(color);
};
render() {
return (
<div style={{ backgroundColor: this.context.color }}>
<select
value={this.context.color}
onChange={(e) =>
this.handleChange(e.target.value)
}
>
<option value="#fff">fff</option>
<option value="#f00">f00</option>
<option value="#f0f">f0f</option>
</select>
</div>
);
}
}
//ColorContext is imported from ColorContext.js
Banner.contextType = ColorContext;
//in file Toolbar.js
class Toolbar extends React.PureComponent {
render() {
return (
<h1 style={{ backgroundColor: this.context.color }}>
Toolbar
</h1>
);
}
}
//ColorContext is imported from ColorContext.js
Toolbar.contextType = ColorContext;
const App = () => (
<div>
<Banner />
<Toolbar />
</div>
);
ReactDOM.render(
<ColorProvider>
<App />
</ColorProvider>,
document.getElementById('root')
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
<div id="root"></div>

Functional Search Bar in TypeScript

I have created a Material UI search bar front-end but for now I am unable to type anything into it. How could I fix this?
export default class userSearchPage extends Component <{}, { searchItem: string}>{
constructor(props: Readonly<{}>) {
super(props);
this.state = {
searchItem: 'ha'
};
}
render() {
return (
<div>
<PermanentDrawerLeft></PermanentDrawerLeft>
<div className='main-content'>
{/* <Typography>{this.state.searchItem}</Typography> */}
<SearchBar
onChange={e => {
this.setState({searchItem: e.target.value})
}}
onRequestSearch={() => console.log('onRequestSearch')}
style={{
margin: '0 auto',
maxWidth: 800
}}
/>
</div>
</div>
);
}
}
The onChange method doesn't work and gives an error.
I feel that this method in general is not the ideal way. How else could I make the search bar functional in Typescript so it could read and store what the user types in?
Try this one
<form onSubmit={props.onRequestChange}>
<input id="searchbartext" onChange={props.onChange} />
</form>

React. onClick event not firing

In my navbar, I have a button that will display a submenu (list of items) when clicked. Each item is their own child component and when clicked I want them to fire an event. The onClick event listener is not responding at all. However, other mouse events do apply (onMouseEnter, onMouseOut etc). Anyone might know what's up?
Child Component: NotificationItem.js
import React from "react"
import { connect } from "react-redux"
import { updateNotification } from "../../actions/notificationActions"
class NotificationItem extends React.Component{
constructor(props){
super(props)
this.handleOnClick = this.handleOnClick.bind(this)
}
handleOnClick = (event) => {
console.log("clicked")
// let notificationId = this.props.notification._id
// this.props.updateNotification(notificationId)
}
render(){
let {avatar, description, seen} = this.props.notification
return(
<div
onClick={this.handleOnClick}
className="d-flex notification-wrapper"
style={ seen ? (
{ width: "250px", whiteSpace: "normal", padding: "0.5rem" }
):( { width: "250px", whiteSpace: "normal", padding: "0.5rem", backgroundColor: "#d7e2f4" }
)
}
>
<div>
<img src={avatar} style={{ width: "25px"}} className="mr-2 rounded-circle"/>
</div>
<div>
{description}
</div>
</div>
)
}
}
Parent component: NotificationFeed.js
import React from "react"
import { connect } from "react-redux"
import NotificationItem from "./NotificationItem"
class NotificationFeed extends React.Component{
constructor(props){
super(props)
}
render(){
let notifications = this.props.notification.notifications
return(
<div className="dropdown-menu">
{notifications.map((notification, index) => {
return(
<div key={index}>
<NotificationItem notification={notification}/>
</div>
)
})}
</div>
)
}
}
const mapStateToProps = (state) => {
return{
notification: state.notification
}
}
export default connect(mapStateToProps)(NotificationFeed)
Edit: Something I noticed that might be of help. I'm using a bootstrap class to create this dropdown toggle-effect. When clicking on one of the items, the submenu closes immediately, without firing my desired event handler on the component.
<span className="dropdown" id="notifications-dropdown">
<Link to="#" className="nav-link text-light dropdown-toggle" data-toggle="dropdown">
<span
key={Math.random()}
>
<i className="fa fa-bell"></i>
</span> { windowWidth < 576 && "Notifications"}
<NotificationFeed/>
</Link>
</span>
For those still interested, this was a problem with Bootstrap. Because the elements were created inside a Bootstrap dropdown it had some logic I couldn't see. Whenever I would click on an element, the dropdown closes before the event-handler would even fire.
Opted, to create my own dropdown instead. Thanks all!
You created an arrow function, you do not need to bind it in the constructor
import React from "react"
import { connect } from "react-redux"
import { updateNotification } from "../../actions/notificationActions"
class NotificationItem extends React.Component{
state = {}
handleOnClick = (event) => {
console.log("clicked")
}
//or do not use arrow function then bind in the constructor
//constructor(props) {
//super(props);
//this.handleOnClick = this.handleOnClick.bind(this)
//}
// handleOnClick(event) {
// console.log("clicked")
// }
render(){
let {avatar, description, seen} = this.props.notification
return(
<div
onClick={this.handleOnClick}
className="d-flex notification-wrapper"
style={ seen ? (
{ width: "250px", whiteSpace: "normal", padding: "0.5rem" }
):( { width: "250px", whiteSpace: "normal", padding: "0.5rem", backgroundColor: "#d7e2f4" }
)
}
>
<div>
<img src={avatar} style={{ width: "25px"}} className="mr-2 rounded-circle"/>
</div>
<div>
{description}
</div>
</div>
)
}
try this
onClick={ (e) => this.handleOnClick(e)}
Try change your code, now it's like method:
handleOnClick(event){
console.log("clicked")
}

How can I display an array of objects inside a object in React?

I am trying to make a mock news react app and I am using newsapi's node package. This returns a response that has an array of objects inside one object. I set the state to the response of the newsapi function and when I log it to the console I get the object. I just can't display it on my site because I don't know how to display a state of objects inside a array.
Here is my App.js:
import React, { Component } from "react";
import Paper from "#material-ui/core/Paper";
import Divider from "#material-ui/core/Divider";
const NewsAPI = require("newsapi");
const newsapi = new NewsAPI("APIKEY");
class App extends Component {
constructor() {
super();
this.state = { articles: {} };
newsapi.v2
.topHeadlines({
category: "business",
language: "en",
country: "us"
})
.then(response => {
this.setState({ articles: { response } });
console.log(this.state.articles.response.articles[2]);
});
}
render() {
let article = this.state.articles;
return (
<div>
<div style={{ display: "flex" }}>
<div
style={{ marginLeft: "23em", width: "75%", paddingBottom: "20px" }}
>
<Paper>
<div style={{ textAlign: "center" }}>
<p style={{ margin: "50px" }}>
<b />
</p>
<br />
</div>
<p>
{article.map(articles => (
<p>{articles.name}</p>
))}
</p>
<br />
<Divider />
</Paper>
<div style={{ textAlign: "center", paddingTop: "20px" }} />
</div>
</div>
</div>
);
}
}
export default App;
I currently get the error that map isn't a function.
Response from API:
// Edited: Changed articles from array to object.
// Thanks to everyone... devserkan's answer helped the most and I can now move on with my project!
First of all as told you should keep your articles state as an array in your state since it is an array in your response. Then you can map it easily. Here is a working example. I am faking API response here but you can use it for your situation.
class App extends React.Component {
state = {
articles: [],
}
response = {
status: "ok",
totalResults: 20,
articles: [
{ author: "foo", title: "bar" },
{ author: "fizz", title: "buzz" },
]
}
getArticles = () =>
new Promise( resolve =>
setTimeout( () => resolve(this.response)), 500)
componentDidMount() {
this.getArticles()
.then(response => this.setState({articles: response.articles}))
}
render() {
const {articles} = this.state;
return (
<div>
{
articles.map( article => (
<div>
<p>Author: {article.author}</p>
<p>Title: {article.title}</p>
</div>
))
}
</div>
);
}
}
ReactDOM.render(<App />, document.getElementById("root"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="root"></div>
For your situation, just look at my example and set your articles state as an empty array. Then use your newsApi call in your componentDidMount method. I'm providing your fixed code here but can't be sure it works since I can't test it.
class App extends Component {
constructor() {
super();
this.state = { articles: [] };
}
getNews = () =>
newsapi.v2
.topHeadlines({
category: "business",
language: "en",
country: "us"
})
.then(response => {
this.setState({ articles: response.articles });
});
componentDidMount() {
this.getNews();
}
render() {
let articles = this.state.articles;
return (
<div>
<div style={{ display: "flex" }}>
<div
style={{ marginLeft: "23em", width: "75%", paddingBottom: "20px" }}
>
<Paper>
<div style={{ textAlign: "center" }}>
<p style={{ margin: "50px" }}>
<b />
</p>
<br />
</div>
<p>
{articles.map(article => (
<p>{article.author}</p>
))}
</p>
<br />
<Divider />
</Paper>
<div style={{ textAlign: "center", paddingTop: "20px" }} />
</div>
</div>
</div>
);
}
}
What have I changed?
Change articles shape in your state.
Create a function to get news: getNews.
In this function get the news and set the articles like this: this.setState({ articles: response.articles })
Add componentDidMount and invoke the created function.
In render method change article name to articles since this is more consistent. Also change articles to article in your map.
There is no name in an article, so I've changed it with author.
You are setting your articles as an object instead of an array.
Then, when you try to "map" your articles, you get an error because object doesn't have a map function.
You can fix this by setting your articles object in your state to be an array:
this.setState({ articles: response.articles });
Note I removed curly braces around the response to prevent creating a new object
map work only for arrays, use for in or foreach
let articles_name = [];
for (var index in this.state.articles) {articles_name.push(<p>this.state.articles[index].name</p>)}
{article.map(articles => <p>{articles.name}</p>)} can be replaced by {articles_name}

How do I clear the the array of a state?

So this is my code :
import React from "react";
import Navigation from './Navigation';
import Foot from './Foot';
import MovieCard from './MovieCard';
class Favorites extends React.Component {
render() {
const { onSearch, favorites, favoriteCallback, totalFavorites, searchKeyUpdate } = this.props;
return (
<div>
<Navigation
onSearch={onSearch}
totalFavorites={totalFavorites}
searchKeyUpdate={searchKeyUpdate} />
<div className="container">
<button onClick={()=> this.clearFavorites(favorites)}> Clear all movies </button>
{(favorites.length < 1) ?
<h1 style={{ fontSize: '13px', textAlign: 'center' }}>Please mark some of the movies as favorites!</h1>
:
<ul
className="movies">
{favorites
.map(movie => (
<MovieCard
movie={movie}
key={movie.imdbID}
toggleFavorite={favoriteCallback}
favorites={favorites}
/>
))}
</ul>
}
<Foot />
</div>
</div>
);
}
}
const clearFavorites = (favorites) => {
this.setState({ favorites: [] });
}
The thing I need for the button to do is that when i click it that it clears the whole state of favorites. The clearFavorites function is used to clear everything but when I try this I get an error:
Why doesn't this clear the state of favorites?
You have two problems:
clearFavorites function is not in your class. So you should put it inside.
You are trying to clear the data inside the favorites array, which is not part of your state, using the function clearFavorites. So, first of all, you should add favorites array to your state and then you can manipulate the information. I suggest you to use the function getDerivedStateFromProps.
As others mentioned, first moving clearFavorites function into Favorites class.
Second, your favorites list is not part of state object, but instead you pull it out from this.props.favorites, so instead of using this.setState, we should just change the props value.
Third, since you're emptying the array, the parameter in your clearFavorites probably not needed? Please refer to below:
First we define a constructor to get the value from props and pass it to state in the constructor as below:
constructor(props) {
super(props);
this.state = {favorites: this.props.favorites}
}
clearFavorites = () => {
this.setState({favorites: []});
};
Then at last in your render method change to following:
const { onSearch, favoriteCallback, totalFavorites, searchKeyUpdate } = this.props;
const favorites = this.state.favorites;// Or in your ul tag, instead of using favorites, change it to this.state.favorites
You can try to move the clearFavorites into your component
import React from "react";
import Navigation from "./Navigation";
import Foot from "./Foot";
import MovieCard from "./MovieCard";
class Favorites extends React.Component {
render() {
const {
onSearch,
favorites,
favoriteCallback,
totalFavorites,
searchKeyUpdate
} = this.props;
return (
<div>
<Navigation
onSearch={onSearch}
totalFavorites={totalFavorites}
searchKeyUpdate={searchKeyUpdate}
/>
<div className="container">
<button onClick={() => this.clearFavorites(favorites)}>
{" "}
Clear all movies{" "}
</button>
{favorites.length < 1 ? (
<h1 style={{ fontSize: "13px", textAlign: "center" }}>
Please mark some of the movies as favorites!
</h1>
) : (
<ul className="movies">
{favorites.map(movie => (
<MovieCard
movie={movie}
key={movie.imdbID}
toggleFavorite={favoriteCallback}
favorites={favorites}
/>
))}
</ul>
)}
<Foot />
</div>
</div>
);
}
clearFavorites = favorites => {
this.setState({ favorites: [] });
};
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>

Categories

Resources