ComponentDidMount isn't running - javascript

My code isn't hitting componentDidMount and returning back the data nor hitting the console.log within componentDidMount. The API is working fine.
It was working fine until I added 'searchTerm' state and onChangeHandler. Any ideas?
Because of that all my component props that I'm sending down is returning undefined.
constructor(props) {
super(props)
this.state = {
allStudents: [],
searchTerm: " ",
}
}
componentDidMount() {
fetch(API)
.then(resp => resp.json())
.then(students => {
console.log("app", students)
this.setState({
allStudents: students.students
})
});
}
onSearchHandler = event => {
console.log(event.target.value)
event.preventDefault();
this.setState({
searchTerm: event.target.value})
}
render () {
const { allStudents, searchTerm} = this.state
return (
<div className="App">
<div>
{console.log(allStudents)}
<input
style={{
width: '100%',
fontSize: 'x-large',
border: '0',
outline: 'none'}}
type='text'
placeholder='search by name...'
onChange={this.onSearchHandler}
/>
</div>
<hr />
<StudentContainer allStudents={allStudents}
searchTerm={searchTerm}
onSearchHandler={this.onSearchHandler} />
</div>
)
}
}
export default App;

Related

React data from Children to Parent, map json

I'm learning ReactJS and I want to map a json in a father component from child search bar. So I got this:
export default class Child extends Component {
constructor(props) {
super(props)
this.state = { data:[], value: '' };
this.handleSubmit = this.handleSubmit.bind(this)
this.handleChange = this.handleChange.bind(this)
}
guardar = (data) => {
this.setState({ data })
this.props.parentCallback({ data })
}
handleChange(e) {
this.setState({ value: e.target.value })
axios.get(`http://localhost:3001/api/search?query=${ e.target.value }`)
.then(( { data } ) => this.guardar(data) )
}
handleSubmit(e) {
e.preventDefault()
}
render() {
return(
<form onSubmit={this.handleSubmit}>
<input type="text"
name='searchbar'
onChange={this.handleChange}/>
</form>
)
}
}
export default class Parent extends Component {
state = {
data: [],
}
handleCallback = (childData) => {
this.setState({
data: childData
})
console.log(this.state.data);
}
render() {
const { data } = this.state
return(
<div>
<SearchBar parentCallback = {this.handleCallback}/>
<ProductCard />
{ [data].map( res => <li key={res.id}>{ res.title }</li>) }
</div>
)
}
}
Here is the result:
I want to map if even if the array is empty, in the console shows me the 50 elements only if I write more than twice in the input and I want them when I reload the page.
Beforehand thank you very much!!

React: Child Component Does Not Rerender When Submitting Form

I am new in React and I will appreaciate much any help. I am using create-react-app, react-router-dom and express server. When I try to submit a comment to a blog post (child component called Details), it gets stored in the database, however the component does not seem to update and i do not see the new comment.As a result, I can see the new comment only after i refresh the page but not on form submit. I guess I am not setting componentDidUpdate properly but I do not have a clue how to do it, so i can see the comment immediately.
Here is my App.js:
class App extends Component {
constructor(props) {
super(props)
this.state = {
userId: null,
username: null,
isAdmin: false,
isAuthed: false,
jwtoken: null,
posts: [],
filtered: [],
}
this.handleSubmit = this.handleSubmit.bind(this)
}
static authService = new AuthService();
static postService = new PostService();
static commentService = new CommentService();
componentDidMount() {
const isAdmin = localStorage.getItem('isAdmin') === "true"
const isAuthed = !!localStorage.getItem('username');
if (isAuthed) {
this.setState({
userId: localStorage.getItem('userId'),
username: localStorage.getItem('username'),
isAdmin,
isAuthed,
})
}
this.getPosts()
}
componentDidUpdate(prevProps, prevState, posts) {
if (prevState === this.state) {
this.getPosts()
}
}
handleChange(e, data) {
this.setState({
[e.target.name]: e.target.value
})
}
handleCommentSubmit(e, data) {
e.preventDefault();
e.target.reset();
App.commentService.createComment(data)
.then(body => {
this.getposts()
if (!body.errors) {
toast.success(body.message);
}
else {
toast.error(body.message);
}
}
)
.catch(error => console.error(error));
}
getPosts() {
App.postService.getPost()
.then(data => {
this.setState({
posts: data.posts.length? data.posts : []
});
}
)
.catch(e => this.setState({ e }))
}
render() {
return (
<Fragment>
<Header username={this.state.username} isAdmin={this.state.isAdmin} isAuthed={this.state.isAuthed} logout={this.logout.bind(this)} />
<Switch>
<Route exact path="/" render={(props) => (
<Home
posts={this.state.posts}
handleSearchSubmit={this.handleSearchSubmit.bind(this)}
handleChange={this.handleSearchChange.bind(this)}
{...props} />
)} />
<Route path="/posts/:id" render={(props) =>
<Details handleSubmit={this.handleCommentSubmit.bind(this)}
isAdmin={this.state.isAdmin}
isAuthed={this.state.isAuthed}
posts={this.state.posts}
handleChange={this.handleChange}
{...props} />} />
</Switch>
<Footer posts={this.state.posts} formatDate={this.formatDate} />
</Fragment>
);
}
}
export default withRouter(App);
Here is my Details.js:
class Details extends Component {
constructor(props) {
super(props);
this.state = {
post: null,
comment: null
}
this.handleChange = props.handleChange.bind(this);
}
componentDidMount() {
const { posts, match } = this.props;
this.setState({
post: posts.length
? posts.find(p => p._id === match.params.id)
: null,
userId: localStorage.getItem('userId')
})
}
componentDidUpdate(prevProps) {
const { posts, match, isAuthed } = this.props;
if (JSON.stringify(prevProps) === JSON.stringify(this.props)) {
return;
}
this.setState({
post: posts.length
? posts.find(p => p._id === match.params.id)
: null
});
}
render() {
const { post } = this.state;
const { isAdmin, isAuthed } = this.props;
if (!post) {
return <span>Loading post ...</span>;
}
return (
<section className="site-section py-lg">
<form onSubmit={(e)=> this.props.handleSubmit(e, this.state)} className="p-5 bg-light">
<div className="form-group">
<label htmlFor="message">Message</label>
<textarea name="comment" id="message" onChange={this.handleChange} cols={30} rows={10} className="form-control" defaultValue={ ""} />
</div>
<div className="form-group">
<input type="submit" defaultValue="Post Comment" className="btn btn-primary" />
</div>
</form>}
</section>
);
}
}
export default Details;
Any help will be much appreciated!
You are doing a mistake that will be done by any new React developer. Just remember one thing that:-
UI is a function of state
So your UI will only be updated if your state is update.
After submitting a comment don't fetch all your comments again, just concat your new comment to current state and you will see your comment as soon as you submit it successfully

handleRemove function for Todo List app with an array of objects

So I am making this app super simple, however I can't get my handleRemove to work properly. filteredTodos comes out to be a list of all the same todos. This is my code.
I have tried even looking at other solutions online but for some reason this filter function in handleRemove does not filter anything out of the state.
import React, { Component } from 'react';
class Main extends Component {
constructor(props){
super(props);
this.state = {
todos: [],
inputValue: '',
};
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
this.handleRemove = this.handleRemove.bind(this);
}
handleChange = (e) => {
e.preventDefault();
this.setState({
inputValue: e.target.value
});
}
handleSubmit = (e) => {
e.preventDefault();
const newTodo = this.state.inputValue;
if (this.state.inputValue === ''){
alert('Please Enter a Todo!');
} else {
this.setState((prevState) => ({
todos: [...prevState.todos,
{
message: newTodo,
id: this.state.todos.length
}
]
}));
this.setState({inputValue:''});
}
}
handleRemove (id) {
const filteredTodos = this.state.todos.filter(todo => todo.id !== id);
this.setState({
todos: filteredTodos
});
console.log(filteredTodos);
}
render(){
const mappedTodos = this.state.todos.map((item, i) =>
<div key={i} id={this.state.todos[i].id}>
{item.message} <button type='submit' onClick={this.handleRemove}>X</button>
</div>
)
return(
<div className='main-page'>
<div className='input'>
<input type='text' placeholder='Enter Your Todo' value={this.state.inputValue} onChange={this.handleChange} />
<button type='submit' onClick={this.handleSubmit}>Add</button>
</div>
<div className='todos'>
{mappedTodos}
</div>
</div>
)
}
}
export default Main;
Your handleRemove function requires an id you can see it by the value in the round brackets
handleRemove (id)
to fix the problem you just have to pass the parameter just like this:
const mappedTodos = this.state.todos.map((item, i) =>
<div key={i} id={this.state.todos[i].id}>
{item.message} <button type='submit' onClick={this.handleRemove(this.state.todos[i].id)}>X</button>
</div>
)

Fetch data, function Error() { [native code] } <constructor>: "Function"

I am trying to fetch API with react, however when I console it, it shows
parsing failed
function Error() { [native code] }
<constructor>: "Function"
name: "Function".
and I created a buttons inside the panel, when i click each button, the screen should show different information base on the data that i fetch from Api, however, when i trying to fetch API the buttons are not display in the screen anymore and the avatar image that I want to show on top of the information is also not display in the panel anymore, I have no idea where wrong. Also, the API url that I used only can random 500 results for each day. But I don't think this is the problem, since I try to use another link, it still a same problem. Thanks for your help!
index.js
const url = 'https://beta.randomapi.com/api/9qvib112?key=X7E9-7CWN-4TY0-7GZT&results=12';
class App extends Component {
constructor(props) {
super(props);
this.state = {
contacts: []
}
}
componentDidMount() {
this.fetchdata();
}
fetchdata() {
fetch(url)
.then(Response => Response.json())
.then(parsedJSON => console.log(parsedJSON.results.map(users => (
{
name: `${users.user.first} ${users.user.last}`,
birthday: `${users.birthday}`,
email: `${users.email}`,
address: `${users.address}`,
phone: `${users.phone}`,
password: `${users.password}`,
image: `${users.image}`,
}
))))
.then(contacts => this.setState({
contacts,
}))
.catch(erro => console.log('parsing failed', Error))
}
render() {
const {contacts} = this.state;
return (
<div className="panel">
{
contacts.length > 0 ? contacts.map(contact => {
return
<div class="panel">
<Panel
avatar={contact.image}
/>
<li class="flex-container">
<Button title="user">
<Panel user={contact.name} />
</Button>
<Button title="email">
<Panel user={contact.email} />
</Button>
<Button title="birthday">
<Panel user={contact.birthday} />
</Button>
<Button title="address">
<Panel user={contact.address} />
</Button>
<Button title="phone">
<Panel user={contact.phone} />
</Button>
<Button title="password">
<Panel user={contact.password} />
</Button>
</li>
</div>
}) : null
}
</div>
);
}
}
ReactDOM.render(
<App />,
document.getElementById("root")
);
ProfilePanel.js
const style={
borderRadius: 150,
}
class Panel extends Component {
constructor(props){
super(props);
this.state = {
avatar: "",
user: ""
}
}
render() {
const { avatar, user } = this.state;
return (
<div className="Panel">
<div class="panels">
<div className="avatar">
<img src={avatar} style={style}/>
</div>
</div>
<div class="center">
<h2 className="user">{user}</h2>
</div>
</div>
);
}
}
export default Panel;
Button.js
import './index.css';
import React, { Component } from 'react';
const styles = {
color: 'white',
background: '#0288d1',
margin: '20px',
width: 150,
height: 40,
borderRadius: 50,
marginTop: 0,
marginBottom: 40,
}
class Button extends Component {
constructor(props) {
super(props);
this.state = {
open:false,
};
}
render() {
const { title, children} = this.props;
const {open} = this.state;
return (
<div className={` ${open ? 'open' : ''}`}
class='button' onClick={(e) => this.handleClick(e)}>
<div className="panel-heading">
<h2 class='buttoncenter'>{title}</h2>
</div>
<div className="panel-collapse">
<div className="panel-body">
{children}
</div>
</div>
</div>
);
}
handleClick(e) {
e.preventDefault();
this.setState({
open: !this.state.open
})
}
}
export default Button;
In your fetch method, you're using an interface .then(Response => Response.json())
Try renaming it to something else like .then(res => res.json())
In index.js you're passing props to Panel and Button, but only Button is using them.
ProfilePanel.js const { avatar, user } = this.state; Change it to this.props
You could also just pass the "parsedJSON" in the .then directly to the state and then map through it like you're doing in the render method.
In your index.js file
Inside your fetchData() function
fetchdata() {
fetch(url)
.then(Response => Response.json())
.then(parsedJSON => console.log(parsedJSON.results.map(users => (
{
// Your Code
}
))))
.then(contacts => this.setState({contacts}))
.catch(error => console.log('parsing failed', Error()))
}
The Error in the catch statement is a function. You are using it as a property. Hence to get the the output of that function, you need to add parenthesis() after it.

Component Not Re-Rendering After Props Are Changed

I'm passing a search input prop (searchTerm) to a React component (Graph).
It appears in dev tools that the Graph component is receiving the correct prop and state is being updated, but my fetch api function is not re-rendering the new data based on the updated prop. If I manually force data to the API url, the fetch works, so I know it has to be a way i'm passing the searchTerm. I've tried every iteration possible, but still can't get it to work. Any ideas?
class Graph extends Component {
constructor(props){
super(props);
this.state = {
loaded: false,
now: Math.floor(Date.now()/1000),
data1: [],
searchTerm: DEFAULT_QUERY
}
this.getData = this.getData.bind(this)
}
componentDidMount() {
const {now, searchTerm} = this.state;
this.getData(now, searchTerm);
}
componentWillReceiveProps(nextProps) {
this.setState({searchTerm: nextProps.searchTerm });
}
componentDidUpdate(prevProps) {
const {now, searchTerm} = this.state;
if(this.props.searchTerm !== prevProps.searchTerm) {
this.getData(now, searchTerm);
}
}
getData = (now=this.state.now, searchTerm=this.state.searchTerm) => {
let ticker = searchTerm.toUpperCase();
console.log(searchTerm);
fetch(`https://poloniex.com/public?
command=returnChartData&currencyPair=USDT_${ticker}&end=${now}&period=14400&start=1410158341`)
.then(res => res.json())
.then(results => {
this.setState({
data1:results.map(item => {
let newDate = (item.date)*1000; //*1000
return [newDate,item.close]
})
})
console.log(JSON.stringify(this.state.data1));
})
.then(()=> {
const {data1} = this.state;
this.setState({
min: data1[0][0],
max: data1[data1.length-1][0],
loaded: true})
})
})
}
render() {
const {data1, min, max} = this.state;
return (
<div className="graph">
<HighchartsStockChart>
<Chart zoomType="x" />
<Title>Highstocks Example</Title>
<Loading isLoading={!this.state.loaded}>Fetching data...</Loading>
<Legend>
<Legend.Title></Legend.Title>
</Legend>
<RangeSelector>
<RangeSelector.Button count={1} type="day">1d</RangeSelector.Button>
<RangeSelector.Button count={7} type="day">7d</RangeSelector.Button>
<RangeSelector.Button count={1} type="month">1m</RangeSelector.Button>
<RangeSelector.Button type="all">All</RangeSelector.Button>
<RangeSelector.Input boxBorderColor="#7cb5ec" />
</RangeSelector>
<Tooltip />
<XAxis min={min} max={max}>
<XAxis.Title>Time</XAxis.Title>
</XAxis>
<YAxis id="price">
<YAxis.Title>Price</YAxis.Title>
{this.state.loaded &&<AreaSplineSeries id="price" name="Price" data={data1} />}
</YAxis>
<Navigator>
<Navigator.Series seriesId="profit" />
</Navigator>
</HighchartsStockChart>
</div>
);
}
}

Categories