Child component is not updating from parent state change - javascript

I'm trying to update my child component's photos from the parent components state. For all the other routes, the appropriate function was already invoked once the app was mounted. The component that renders cats, dogs, or computers is PhotoList.js
But now, I want to be able to enter a parameter after search (ex. /search/:id) and run a function called getImages in my Container.js to search for any type of picture from the Flickr API.
I tried using componentDidMount and invoking the getImages function with the match parameter inside of it but it doesn't seem to change the data props that's put into it. Does anyone have any suggestions as to how I can make this?
Here is Container.js
import React, {Component} from 'react';
import Photo from './Photo';
class Container extends Component {
componentDidMount() {
this.props.getImages(this.props.match.id)
}
render() {
return (
<div className="photo-container">
<h2>Results</h2>
<ul>
{this.props.data.map((photo,index)=>
<Photo
farm={photo.farm}
server={photo.server}
id={photo.id}
secret={photo.secret}
key={index}
/>
)}
</ul>
</div>
);
}
}
export default Container
Here is PhotoList.js
import React, {Component} from 'react';
import Photo from './Photo';
import NoResults from './NoResults';
class PhotoList extends Component {
render() {
return (
<div className="photo-container">
<h2>Results</h2>
<ul>
{this.props.data.map((photo,index)=>
<Photo
farm={photo.farm}
server={photo.server}
id={photo.id}
secret={photo.secret}
key={index}
/>
)}
</ul>
</div>
);
}
}
export default PhotoList;
Here is App.js
import React, {Component} from 'react';
import {
BrowserRouter,
Route,
Switch,
Redirect
} from 'react-router-dom';
import Search from './Search';
import Nav from './Nav';
import '../index.css';
import axios from 'axios';
import apiKey from './Config';
import NotFound from './NotFound';
import PhotoList from './PhotoList';
import NoResults from './NoResults';
import Container from './Container';
class App extends Component {
state= {
cats: [],
dogs: [],
computers: [],
searchResult: [],
loading: true
}
componentDidMount() {
this.getCats()
this.getDogs()
this.getComputers()
}
getCats=(query='cats')=> {
axios.get(`https://www.flickr.com/services/rest/?method=flickr.photos.search&api_key=${apiKey}&tags=${query}&per_page=24&page=1&format=json&nojsoncallback=1`)
.then(res=> {
const cats=res.data.photos.photo
this.setState({cats})
}).catch((error)=> {
console.log("There was an error parsing your data", error);
})
}
getDogs=(query='dogs')=> {
axios.get(`https://www.flickr.com/services/rest/?method=flickr.photos.search&api_key=${apiKey}&tags=${query}&per_page=24&page=1&format=json&nojsoncallback=1`)
.then(res=> {
const dogs=res.data.photos.photo
this.setState({dogs})
}).catch((error)=> {
console.log("There was an error parsing your data", error);
})
}
getComputers=(query='computers')=> {
axios.get(`https://www.flickr.com/services/rest/?method=flickr.photos.search&api_key=${apiKey}&tags=${query}&per_page=24&page=1&format=json&nojsoncallback=1`)
.then(res=> {
const computers=res.data.photos.photo
this.setState({computers});
}).catch((error)=> {
console.log("There was an error parsing your data", error);
})
}
getImages=(query)=> {
axios.get(`https://www.flickr.com/services/rest/?method=flickr.photos.search&api_key=${apiKey}&tags=${query}&per_page=24&page=1&format=json&nojsoncallback=1`)
.then (res=> {
const searchResult=res.data.photos.photo
this.setState({searchResult});
}).catch((error)=> {
console.log("There was an error parsing your data", error);
})
}
render() {
return (
<div className="container">
<Search getImages={this.getImages}/>
<Nav />
<Switch>
<Route exact path="/" render={()=> <Redirect to={'/cats'} />} />
<Route path='/cats' render={()=> <PhotoList data={this.state.cats}/>} />
<Route path='/dogs' render={()=> <PhotoList data={this.state.dogs} />} />
<Route exact path='/computers' render={()=> <PhotoList data={this.state.computers} />} />
<Route path='/search/:id' render={(props)=> <Container {...props} getImages={this.getImages} data={this.state.searchResult} />} />
<Route component={NotFound}/>
</Switch>
</div>
)
}
}
export default App;

Assuming your are using react-router-dom 4 and above.
Try
import React, { Component } from "react";
import { withRouter } from "react-router-dom"; //<-- import this
import Photo from "./Photo";
class Container extends Component {
componentDidMount() {
// Your this.props.match.id is likely undefined
this.props.getImages(this.props.match.params.id); // <-- Change here
}
...
}
export default withRouter(Container); // <-- Change this

Related

Unable to console.log props using Link

I am trying to make a single web application. Basically, I am trying to use the ReactRouter to display what is passed as a Route Parameter. However, I am unable to do that. To check if somethings wrong, I decided to console.log out this.props.match, still nothing shows up. Could someone explain what the problem is? And a possible get around?
My code is-
import React from 'react';
export default class Post extends React.Component {
state = {
id: null
}
componentDidMount(props) {
console.log(this.props.match);
}
render = () => {
return (<div>Hello WOrld</div>)
}
}
The App.js file:
import React, { Fragment, Component } from 'react';
import Navbar from './components/Navbar';
import Home from './components/Home';
import Contact from './components/Contact';
import About from './components/About'
import Post from './components/Post';
import { BrowserRouter, Route } from 'react-router-dom';
class App extends Component {
render = () => {
return (
<BrowserRouter>
<div className="App">
<Navbar />
<Route exact path="/" component={Home} />
<Route path="/contact" component={Contact} />
<Route path="/about" component={About} />
<Route path="/:post-id" component = {Post} />
</div>
</BrowserRouter>
);
}
}
export default App;
I just ran your code on my end, it looks like the problem is using /:post-id. I changed that to /:pid and it worked. I got the below object when I console log this.props.match
{
"path":"/:pid",
"url":"/1",
"isExact":true,
"params":
{
"pid":"1"
}
}
I hope this helps.
You have to load the component with router
try this
import { withRouter } from 'react-router-dom';
class Post extends React.Component {
state = {
id: null
}
componentDidMount(props) {
console.log(this.props.match);
}
render = () => {
return (<div>Hello WOrld</div>)
}
}
export default withRouter(Post);

Faced TypeError: render is not a function when using Context API

I am new to React ans was learning Context API and during the use of it I faced this error TypeError: render is not a function. I also found the this answer React Context: TypeError: render is not a function in the platform which is close to my problem but no result. Here is the code I am using:
import React, { Component } from "react";
import MyContext from "../../Containers/Context/Context";
class Track extends Component {
render() {
return (
<MyContext>
{value => {
return <div>{value.heading}</div>;
}}
</MyContext>
);
}
}
export default Track;
import React, { Component } from "react";
const Context = React.createContext();
export class MyContext extends Component {
state = { track_list: [], heading: "Top Ten Tracks" };
render() {
return (
<Context.Provider value={this.state}>
{this.props.children}
</Context.Provider>
);
}
}
export default MyContext = Context.Consumer;
import React, { Component, Fragment } from "react";
import "./App.css";
import Header from "../src/Components/Header/Header";
import Search from "../src/Components/Search/Search";
import Tracks from "../src/Components/Tracks/Tracks";
import { BrowserRouter as Router, Route, Link, Switch } from "react-router-dom";
import NotFound from "./Components/NotFound/NotFound";
import MyContext from "./Containers/Context/Context";
class App extends Component {
render() {
return (
<MyContext>
<Router>
<Fragment>
<Header />
<div className="container">
<Search />
<Switch>
<Route exact path="/" component={Tracks} />
<Route component={NotFound} />
</Switch>
</div>
</Fragment>
</Router>
</MyContext>
);
}
}
export default App;
Your export and import statements are problematic.
first you export class MyContext then you immediately overwrite MyContext with Context.Consumer.
Fix your export statements and then fix your imports. import the Context.Consumer in file Track, and import the Context.Provider in file App
Containers/Context/Context.js
import React, { Component } from "react";
const Context = React.createContext();
class MyContextProvider extends Component {
state = { track_list: [], heading: "Top Ten Tracks" };
render() {
return (
<Context.Provider value={this.state}>
{this.props.children}
</Context.Provider>
);
}
}
const MyContextConsumer = Context.Consumer;
export {MyContextProvider,MyContextConsumer};
Track.js
import React, { Component } from "react";
import {MyContextConsumer} from "../../Containers/Context/Context";
class Track extends Component {
render() {
return (
<MyContextConsumer>
{value => {
return <div>{value.heading}</div>;
}}
</MyContextConsumer>
);
}
}
export default Track;
App.js
import React, { Component, Fragment } from "react";
import "./App.css";
import Header from "../src/Components/Header/Header";
import Search from "../src/Components/Search/Search";
import Tracks from "../src/Components/Tracks/Tracks";
import { BrowserRouter as Router, Route, Link, Switch } from "react-router-dom";
import NotFound from "./Components/NotFound/NotFound";
import {MyContextProvider} from "./Containers/Context/Context";
class App extends Component {
render() {
return (
<MyContextProvider>
<Router>
<Fragment>
<Header />
<div className="container">
<Search />
<Switch>
<Route exact path="/" component={Tracks} />
<Route component={NotFound} />
</Switch>
</div>
</Fragment>
</Router>
</MyContextProvider>
);
}
}
export default App;

How to clear the screen before rendering

Seeing issues while developing a real time wallboard using react . I am displaying 2 components one after another Dashboard1( a table with data), Dashboard2(another table with data) with 3 secs time interval. My parent component is Dashboard it connects to my firestore DB to receive real-time updates and sends this data to Dashboard1 component and then Dashboard 1 renders its data and after 3 seconds calls Dashboard2 with the same data passed to it by Dashboard using props.history.push().I am seeing 2 issues here. The component Dashboard 2 is always rendered above Dashboard1.Like when i scroll down the page ,i can still see Dashboard1 at the bottom. How to clear off the page before rendering Dashboard1 and 2 .So that i just see a single component at a time on the screen.Below is my code for App, Dashboard ,Dashboard1 and Dashboard2.I am also seeing Dashboard 2 is being rendered multiple times in the console logs.
Kindly help me to fix these 2 issues:
App.js:
import React, { Component } from 'react';
import { BrowserRouter, Route } from 'react-router-dom'
import Dashboard from './components/Dashboard'
import Dashboard1 from './components/Dashboard1'
import Dashboard2 from './components/Dashboard2'
class App extends Component {
render() {
console.log('App')
return (
<BrowserRouter>
<div className="App">
<Route exact path='/' component={Dashboard} />
<Route exact path='/Dashboard1' component={Dashboard1} />
<Route exact path='/Dashboard2' component={Dashboard2} />
<Dashboard />
</div>
</BrowserRouter>
)
}
}
export default(App)
Dashboard.js:
import React, { Component } from 'react';
import { BrowserRouter, Route, Redirect } from 'react-router-dom'
import Dashboard1 from './Dashboard1'
import Dashboard2 from './Dashboard2'
import { connect } from 'react-redux'
import { firestoreConnect } from 'react-redux-firebase'
import { compose } from 'redux'
class Dasboard extends Component {
render() {
console.log('Dashboard')
const { agents } = this.props
if (!agents) {
return null
}
return (
<Dashboard1 data={agents}/>
)
}
}
const mapStateToProps = (state) => {
return {
agents: state.firestore.data.agent_groups
}
}
export default compose(
connect(mapStateToProps),
firestoreConnect([
{ collection: 'agent_groups' }
])
)(Dasboard)
Dashboard1.js:
import React from 'react'
import Table from '../layouts/Table'
import { withRouter } from 'react-router-dom'
const Dashboard1 = (props) => {
console.log('Dashboard1')
setTimeout(() => {
props.history.push({
pathname: '/Dashboard2',
state: { data: props.data.WFM_Inbound_Sales.agents }})
}, 3000);
return (
<div className="dashboard1">
<Table
data={props.data.WFM_Inbound_Sales.agents}
headers={[
{
name: 'Agent',
prop: 'name'
},
{
name: 'Total calls',
prop: 'InboundCalls'
}
]}
/>
</div>
)
}
export default withRouter(Dashboard1)
Dashboard2.js:
import React from 'react'
import Table from '../layouts/Table'
import { withRouter } from 'react-router-dom'
const Dashboard2 = (props) => {
console.log('Dashboard2')
setTimeout(() => {
props.history.push('/')
}, 3000);
return (
<div className="dashboard2">
<Table
data={props.location.state.data}
headers={[
{
name: 'Agent',
prop: 'name'
},
{
name: 'Status',
prop: 'state'
},
{
name: 'Time in status',
prop: 'TimeInCurrentState'
}
]}
/>
</div>
)
}
export default withRouter(Dashboard2)
You need to use switch which will render only one route of the given set like this
class App extends Component {
render() {
console.log('App')
return (
<BrowserRouter>
<div className="App">
<Switch>
<Route exact path='/' component={Dashboard} />
<Route exact path='/Dashboard1' component={Dashboard1} />
<Route exact path='/Dashboard2' component={Dashboard2} />
</Switch>
<Dashboard />
</div>
</BrowserRouter>
)
}
}
Check the doc here

Failed prop type The prop is marked as required but its value is `undefined`

I'm using react v4, and I'm trying to list an array in the page "treinamentos", but I'm getting an error as I load the page:
Failed prop type: The prop treinamentos is marked as required in
Treinamentos, but its value is undefined.
What am I missing here? is it because of the version I'm using?
Treinamentos:
import React from 'react';
import TreinamentosList from './TreinamentosList';
import { connect } from 'react-redux';
import PropTypes from 'prop-types';
class Treinamentos extends React.Component {
render() {
return (
<div>
Treinamentos
<TreinamentosList treinamentos={this.props.treinamentos} />
</div>
);
}
}
Treinamentos.propTypes = {
treinamentos: PropTypes.array.isRequired
}
function mapStateToProps(state) {
return {
treinamentos: state.treinamentos
}
}
export default connect(mapStateToProps)(Treinamentos);
TreinamentosList:
import React from 'react';
import PropTypes from 'prop-types';
export default function TreinamentosList({ treinamentos }) {
const emptyMessage = (
<p>Adicione um treinamento</p>
);
const treinamentosList = (
<p>treinamentos list</p>
);
return (
<div>
{treinamentos.length === 0 ? emptyMessage : treinamentosList}
</div>
);
}
TreinamentosList.propTypes = {
treinamentos: PropTypes.array.isRequired
}
AppRouter:
import React from 'react';
import { BrowserRouter as Router, Route, Switch } from 'react-router-dom';
import Greetings from './components/Greetings';
import SignUp from './components/singup/SignUp';
import NoMatch from './components/NoMatch';
import Treinamentos from './components/Treinamentos';
import NavigationBar from './components/NavigationBar';
const AppRouter = () => (
<Router>
<div className="container">
<NavigationBar />
<Switch>
<Route path="/" component={Greetings} exact={true}/>
<Route path="/signup" component={SignUp}/>
<Route path="/treinamentos" component={Treinamentos}/>
<Route component={NoMatch}/>
</Switch>
</div>
</Router>
);
export default AppRouter;
You definitely are receiving a null object when you request the state from treinamentos reducer, you should check your reducer, return treinamentos as an empty array as a initial state (or whatever your business logic requires).

react router getComponent passing pathvariable

My app.js:
import React from 'react';
import { Router, Route, Link, IndexRoute, hashHistory, browserHistory } from 'react-router';
import Home from './components/home.jsx';
const loadAsync = (promise) => (location, callback) => {
promise
.then(module => callback(null, module.default))
.catch(e => console.warn('Could not load route component', e));
}
class App extends React.Component {
render() {
return(
<Router history={hashHistory}>
<Route path="/" component={Home} />
<Route path="/hello/:foo" getComponent={loadAsync(System.import('./components/hello.jsx'))} />
</Router>
)
}
}
export default App;
My hello.jsx:
import React from 'react';
class Hello extends React.Component {
render() {
return (<h1>Hello {this.props.matches.foo}!</h1>);
}
}
export default Hello;
The home.jsx contains a Link to "/hello/World".
How can read the "foo" variable in hello.jsx?
Do I have to pass it in loadAsync() and how ?

Categories

Resources