I'm trying to import my created context from my App.js, in a child component.
App.js
export const FilterContext = React.createContext("test");
export default class App extends React.Component {
render() {
return (
<div className="App">
<Navigation />
<Hero />
<FilterContext.Provider value="hello">
<OfferSorting />
<div className="wrapper">
<div className="container">
<Offer />
</div>
</div>
<NewOfferButton />
</FilterContext.Provider>
</div>
);
}
}
Then I want to access my context in <OfferSorting />
OfferSorting.js
import { FilterContext } from "../../../App";
export default class OfferSorting extends React.Component {
static contextType = FilterContext;
constructor(props) {
super(props);
}
componentDidMount() {
console.log(this.context)
}
}
But in OfferSorting.js it will throw the error Cannot access 'FilterContext' before initialization. How can I access my context, and not use props?
Related
In my app i have an initial state in a component App.js it's an array of objects
Here is App.js code:
import React, { Component } from 'react';
import './App.css';
import { render } from '#testing-library/react';
// Import Used Components
import SearchBar from '../SearchBar/SearchBar';
import Playlist from '../PlayList/PlayList';
import SearchResults from '../SearchResults/SearchResults';
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
searchResults: [{name: 'name1',artist: 'artist1',album: 'album1',id: 1},
{name: 'name2',artist: 'artist2',album: 'album2',id: 2}]
};
}
// Adding JSX to App Component
render() {
return (
<div>
<h1>Ja<span className="highlight">mmm</span>ing</h1>
<div className="App">
<SearchBar />
<div className="App-playlist">
<SearchResults searchResults={this.state.searchResults} />
<Playlist />
</div>
</div>
</div>
);
}
}
export default App;
I passed this initial state as a prop called searchResults to another component named .
Here is searchResults.js code :
import './SearchResults.css';
import TrackList from '../TrackList/TrackList';
class SearchResults extends React.Component {
render() {
return (
<div className="SearchResults">
<h2>Results</h2>
<TrackList tracks={this.props.searchResults}/>
</div>
);
}
}
export default SearchResults;
then I used passed this prop to another component called TrackList
here is TrackList.js code:
import React from 'react';
import './TrackList.css';
import Track from '../Track/Track';
class TrackList extends React.Component {
render() {
return(
<div className="TrackList">
{
this.props.tracks.map(track => {
return <Track track={track} key={track.id} />;
} )
}
</div>
);
}
}
export default TrackList;
In Track.js I want to map through this initial state array to render a component called Track
here is the Track.js code:
import React from 'react';
import './Track.css';
class Track extends React.Component {
renderAction() {
if (this.props.isRemoval){
return <botton className='Track-action'>-</botton>;
} else {
return <botton className='Track-action'>+</botton>;
}
};
render() {
return (
<div className="Track">
<div className="Track-information">
<h3>{this.props.track.name}</h3>
<p>{this.props.track.artist} | {this.props.track.album}</p>
</div>
<button className="Track-action">{this.renderAction}</button>
</div>
);
}
}
export default Track;
But something is wrong !! I keep getting this error:
TypeError: Cannot read property 'map' of undefined
Here is searchBar.js component code:
import React from 'react';
import './SearchBar.css';
class SearchBar extends React.Component {
render() {
return (
<div className="SearchBar">
<input placeholder="Enter A Song, Album, or Artist" />
<button className="SearchButton">SEARCH</button>
</div>
);
}
}
export default SearchBar;
HERE LINK TO THE PROJECT WITH THE SAME ERROR ON SANDBOX
https://codesandbox.io/s/upbeat-dawn-lwbxb?fontsize=14&hidenavigation=1&theme=dark
Change your TrackList component to this:
class TrackList extends React.Component {
render() {
return (
<div className="TrackList">
{this.props.tracks && this.props.tracks.map(track => {
return <Track key={track.id} track={track}/>
})}
</div>
);
}
}
You can't map through this.props.tracks if it is undefined.
The && (AND operator) is a concise way to conditionally render in React. You can think of it like a simple if statement: If the expression on the left is true, then do x.
I'll also expand on why the this.props.tracks was undefined in a certain instance in your case.
The reason that this problem is happening is your Playlist component. If you uncomment this component from your App you will notice your original code will work.
This is because your PlayList component, like your SearchResults component, also renders your TrackList component. The problem is you haven't passed your state and props down to TrackList like you did with your SearchResults component.
So an alternative solution would be to pass your state and props down from PlayList to TrackList:
App.js
// ...
<SearchResults searchResults={this.state.searchResults} />
<Playlist searchResults={this.state.searchResults}/>
// ...
PlayList.js
// ...
<TrackList tracks={this.props.searchResults}/>
// ...
I have implemented React Context API and I am trying to update the state defined inside the Provider via an onClick function inside a child component.
This is what I have done so far, in the App.js I have:
import { createContext } from 'react';
const MyContext = React.createContext();
export class MyProvider extends Component {
state = {
currPrj: ''
}
handleBtnClick = prjCode => {
this.setState({
currPrj: prjCode
})
}
render() {
return(
<MyContext.Provider value={{
state: this.state
}}>
{this.props.children}
</MyContext.Provider>
)
}
}
export const MyComsumer = MyContext.Consumer;
Inside my child component I have:
import React, { Component } from "react";
import { BrowserRouter as Router, Route, Link } from "react-router-dom";
import { MyComsumer } from "../../index";
export class ProjectCard extends Component {
constructor(props) {
super(props);
this.state = {
// currPrj: ''
};
}
render() {
return (
<MyComsumer>
{(context) => (
<div className="card card-project">
<p>{context.state.currPrj}</p>
<div className="content">
<div className="author">
<Link to={ `projects/${this.props.code}/detail/info` } onClick={() => handleBtnClick(this.props.code) }>
<h4 className="title">
{this.props.title}
</h4>
</Link>
</div>
</div>
)}
</MyComsumer>
);
}
}
export default ProjectCard;
This way I get the following error
Failed to compile
./src/components/ProjectCard/ProjectCard.jsx
Line 32: 'handleBtnClick' is not defined no-undef
Search for the keywords to learn more about each error.
I don't get it why, because:
<p>{context.state.currPrj}</p>
throws no error...
Plus, is this.props.code passed correctly to the function?
Many thanks.
you can follow this:
My Fiddle: https://jsfiddle.net/leolima/ds0o91xa/1/
class Parent extends React.Component {
sayHey(son) {
alert('Hi father, this is son '+son+' speaking');
}
render() {
const children = React.Children.map(this.props.children, (child, index) => {
return React.cloneElement(child, {
someFunction: () => this.sayHey(index)
});
});
return (<div>
<b>Parent</b>
<hr />
{children}
</div>);
}
}
class Child extends React.Component {
render() {
return <div>
<button onClick={() => this.props.someFunction()}>Child</button>
</div>;
}
}
ReactDOM.render(
<Parent>
<Child />
<Child />
</Parent>,
document.getElementById('container')
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="container">
</div>
There is linter error because handleBtnClick is not defined. It's a method of another class, not standalone function.
It's not available in the scope of context consumer function. If consumers are supposed to update the context, updater function should be a part of the context:
<MyContext.Provider value={{
state: this.state,
update: this.handleBtnClick
}}>
And used like:
context.update(this.props.code)
How to access the state variable testState from the different class UserAuthentication?
I have tried this without success:
import React from 'react';
import UserAuthenticationUI from './UserAuthentication/UserAuthenticationUI';
class App extends React.Component {
constructor(props) {
super(props);
this.userAuthenticationUI = React.createRef();
this.state={
testState: 'test message'
}
}
render() {
return(
<div>
<UserAuthenticationUI ref={this.userAuthenticationUI} />
<div>
)
}
}
export default App;
How to access this.state.teststate from class UserAuthenticationUI?
import React from "react";
import App from '../App';
class UserAuthenticationUI extends React.Component {
constructor(props) {
super(props);
this.app = React.createRef();
}
render() {
return(
<div>
<App ref={this.app} />
{console.log(this.state.testState)}
</div>
)
}
}
export default UserAuthenticationUI;
You need to pass it via props.
import React from "react";
import UserAuthenticationUI from "./UserAuthentication/UserAuthenticationUI";
class App extends React.Component {
constructor(props) {
super(props);
this.userAuthenticationUI = React.createRef();
this.setParentState = this.setParentState.bind(this);
this.state = {
testState: "test message"
};
}
setParentState(newStateValue){ // this is called from the child component
this.setState({
testState: newStateValue
})
};
render() {
return (
<div>
<UserAuthenticationUI
stateVariable={this.state.testState}
ref={this.userAuthenticationUI}
setParentState={this.setParentState}
/>
</div>
);
}
}
export default App;
UserAuthenticationUI:
import React from "react";
import App from "../App";
class UserAuthenticationUI extends React.Component {
constructor(props) {
super(props);
this.app = React.createRef();
this.onClick = this.onClick.bind(this);
}
onClick(){
const newStateValue = 'new parent state value';
if(typeof this.props.setParentState !== 'undefined'){
this.props.setParentState(newStateValue);
}
}
render() {
const stateProps = this.props.stateVariable;
return (
<div>
<App ref={this.app} />
<div onClick={this.onClick} />
{console.log(stateProps)}
</div>
);
}
}
export default UserAuthenticationUI;
You should think differently.
Try to read the variable via GET methods and set via SET methods.
Do not try to call the variable immediately
Hope this helps.
you can pass it through Props:
import React from 'react';
import UserAuthenticationUI from
'./UserAuthentication/UserAuthenticationUI';
class App extends React.Component {
constructor(props) {
super(props);
this.userAuthenticationUI = React.createRef();
this.state={
testState: 'test message'
}
}
render(){
return(
<div>
<UserAuthenticationUI testState={this.state.testState} />
<div>
)}
}
export default App;
UserAuthenticationUI:
import React from "react";
import App from '../App';
class UserAuthenticationUI extends React.Component
{
constructor(props){
super(props);
}
render(){
return(
<div>
<App/>
{console.log(this.props.testState)}
</div>
)}
}
export default UserAuthenticationUI;
You can access it via props:
<div>
<UserAuthenticationUI testState={this.state.testState} ref={this.userAuthenticationUI} />
<div>
and in UserAuthenticationUI class access it:
<div>
<App ref={this.app} />
{console.log(this.props.testState)}
</div>
I am using BrowserRouter with App as parent component and UserInfo as child. Unable to fetch data I am getting errors as mentioned in question I am using BrowserRouter with App as parent component and UserInfo as child. Unable to fetch data I am getting errors as mentioned in question
// This is my index.js
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import registerServiceWorker from './registerServiceWorker';
import { BrowserRouter, Switch, Route } from 'react-router-dom'
var UserInfo = require('./Components/UserInfo');
var routes = (
<BrowserRouter>
<Route path="/" component={App}>
<Switch>
<Route path="user/:username" component={UserInfo} />
</Switch>
</Route>
</BrowserRouter>
);
ReactDOM.render(routes, document.getElementById('root'));
registerServiceWorker();
//App.js
import React, { Component } from 'react';
import './App.css';
import PropTypes from "prop-types";
import { browserHistory } from 'react-router';
var history = require('react-router').browserHistory;
class App extends Component {
static contextTypes = {
router: PropTypes.object
}
constructor(props, context) {
super(props, context);
}
submitUser(event) {
console.log(this.refs.inputUser.value);
event.preventDefault();
this.context.router.history.push('/user/${this.refs.inputUser.value}');
}
render() {
return (
<div>
<nav className="uk-navbar-container uk-margin" uk-navbar="true">
<div className="uk-navbar-left">
<a className="uk-navbar-item uk-logo" href="/"> Github search
<span uk-icon="icon: github; ratio: 2.2" className="uk-margin-large-right"></span>
</a>
<div className="uk-navbar-item uk-navbar-right">
<form onSubmit={this.submitUser}>
<input className="uk-input uk-form-width-medium"
type="text" placeholder="Github UserName...." ref="inputUser" />
<button className="uk-button uk-button-primary">Search
<span uk-icon="search" className="uk-margin-small-right"></span>
</button>
</form>
</div>
<div className="uk-navbar-item uk-navbar-right"></div>
</div>
</nav>
<div className="uk-container-large">
{this.props.children}
</div>
</div>
);
}
}
export default App;
//UserInfo.js
import React, { Component } from 'react';
import { BrowserRouter, Link } from 'react-router-dom'
var $ = require('jquery');
class UserInfo extends Component {
constructor(props) {
super(props)
}
getInitialState() {
return {};
}
componentDidMount() {
this.fetchData();
}
componentDidUpdate(prevProps) {
if (prevProps.params.username !== this.props.params.username) {
this.fetchData();
}
}
fetchData() {
$.getJSON('https://api.github.com/users/${this.props.params.username}')
.then(res => res.json())
.then((user) => {
this.setState = { user: user }
});
}
render() {
if (!this.state.user) {
return (
<div className="uk-child-width-1-3#s uk-grid-match">Loading......</div>
)
}
var user = this.state.user;
return (
<div className="uk-child-width-1-3#s uk-grid-match" uk-grid>
<Link to={`/user/${user.login}`}>
<div className="uk-grid-small uk-flex-middle" uk-grid>
<div className="uk-width-auto">
<img className="uk-border-circle" width="60" height="60"
src={user.avatar_url} />>
</div>
<div className="uk-width-expand">
<h3 className="uk-card-title uk-margin-remove-bottom">
{user.login} ({user.name})
</h3>
<p className="uk-text-meta uk-margin-remove-top">
{user.bio}
</p>
</div>
</div>
</Link>
</div>
);
}
}
export default UserInfo;
You have some errors in the UserInfo Component.
You have not set the Initial State of user in the constructor.
No need for another then in $.getJSON().You already getting the response , just setState the user with the response and you are good to go.
class UserInfo extends React.Component {
constructor(props) {
super(props)
this.state={
user : "",
}
}
componentDidMount() {
this.fetchData();
}
componentDidUpdate(prevProps) {
if (prevProps.params.username !== this.props.params.username) {
this.fetchData();
}
}
fetchData() {
$.getJSON('https://api.github.com/users/subhanshu')
.then((res) => {
this.setState({ user : res })
},this);
}
render() {
if (!this.state.user) {
return (
<div className="uk-child-width-1-3#s uk-grid-match">Loading......</div>
)
}
var user = this.state.user;
return (
<div className="uk-child-width-1-3#s uk-grid-match" uk-grid>
<Link to={`/user/${user.login}`}>
<div className="uk-grid-small uk-flex-middle" uk-grid>
<div className="uk-width-auto">
<img className="uk-border-circle" width="60" height="60"
src={user.avatar_url} />>
</div>
<div className="uk-width-expand">
<h3 className="uk-card-title uk-margin-remove-bottom">
{user.login} ({user.name})
</h3>
<p className="uk-text-meta uk-margin-remove-top">
{user.bio}
</p>
</div>
</div>
</Link>
</div>
);
}
}
Your <BrowserRouter> should be like,
<BrowserRouter>
<Switch>
<Route path="/" component={App}>
</Switch>
</BrowserRouter>
and if App is not a generic parent and is used only to show UserInfo, inside the App component's render you can give,
<div className="uk-container-large">
<Route path="user/:username" component={UserInfo} />
</div>
I have a simple component like this
import { Component } from 'react'
export default class SearchList extends Component(){
constructor(props){
super(props);
}
render(){
const { placeholder } = this.props;
return(
<div className="searchList">
<input type="text" placeholder={placeholder}/>
<button>Search</button>
</div>
)
}
}
The somewhere I do <SearchList placeholder="Search Area" />
Why I got error of cannot set property of props of undefined?
When you write a react component extending React.Component you don't need the extra () after React.Component
Use this
export default class SearchList extends Component{
constructor(props){
super(props);
}
render(){
const { placeholder } = this.props;
return(
<div className="searchList">
<input type="text" placeholder={placeholder}/>
<button>Search</button>
</div>
)
}
}