Render map not displaying data on screen - reactjs

I can't seem to get my renderJob mapping to render out properly. I have no errors in the console and can't figure out while nothing is showing up. Is there a problem with the way I'm mapping the object to the index?
import React, { Component } from 'react'
import PropTypes from 'prop-types'
const jbSampleData = [
{
name: 'A place',
location: 'USA',
engineer: "Contact Engineer",
service: "Last install"
},
]
class Job extends Component {
render() {
const renderJob = this.props.data.map((obj, idx) => {
return (
<div key={idx}>
<div>
<p>
<span>Name:</span> {obj.name} < br/>
<span>Location:</span> {obj.location} <br />
<span>Engineer Contact:</span> {obj.engineer} <br />
<span>Service:</span> {obj.service} <br />
</p>
</div>
</div>
);
});
return (
<div>
<renderJob />
Hello
</div>
)
}
}
Job.propTypes = {
data: PropTypes.arrayOf(
PropTypes.object
)
}
Job.defaultProps = {
data: jbSampleData
}
export default Job;

You are storing the map result basically an array in a variable renderJob, that is not a react component.
You need to render it like this:
return (
<div>
{renderJob}
Hello
</div>
)
Basically <renderJob> will get converted into:
React.createElement(renderJob, null); //new custom element
But in case of {renderJob} its value will get replaced, and all the ui items that variable is having will get rendered.
Why it is not throwing the error with <renderJob/> ?
Because name is stated with small letter so it will be considered as a built-in component like div etc, if you use <RenderJob/> it will throw error that RenderJob is not defined.
As per DOC:
When an element type starts with a lowercase letter, it refers to a
built-in component like <div> or <span> and results in a string 'div'
or 'span' passed to React.createElement. Types that start with a
capital letter like <Foo /> compile to React.createElement(Foo) and
correspond to a component defined or imported in your JavaScript file.

Instead of <renderJob /> change to {renderJob}

Related

Is it possible to render a react class when given its name as a string?

Here's a smaller example of what I'm trying to do, I don't know if it's possible to do something similar or I should use an entirely different method.
import {Design1, Design2} from './page-designs';
let designs = {
"page1":"Design1",
"page2":"Design2",
"page3":"Design1",
"page4":"Design2"
}
class DesignedPage extends React.Component {
let Design = designs[this.props.page]
render(){
return(
<div className="row flex-fill d-flex">
<div className="col-1"></div>
<Design /* This is the line that fails */
data = {this.props.data}
/>
</div>
</div>
)}
}
class Main extends React.Component {
render(){
return(
<DesignedPage
page = {this.props.openPage} /*this could be any of page1-4 depending on button a click*/
data = {this.props.data}
/>
)}
}
Ideally this would render the react elements Design1 or Design2 based on what props.page is passed, but instead it returns
"Warning: <Design1 /> is using incorrect casing. Use PascalCase for React components, or lowercase for HTML elements." and "The tag <Design1> is unrecognized in this browser. If you meant to render a React component, start its name with an uppercase letter."
I've thought of making a long if, elseif, elseif.. statement in DesignedPage (the actual code has many more than 2 designs), which I'm fairly confident would work, but looks very messy in comparison.
You can't render the component name by getting its name as a string. You need to map the string to the component iteself:
let designs = {
"page1":Design1,
"page2":Design2,
}
If you pass a string, react would think it's a HTML tag, hence it say'Design1' tag is unrecognised. Also, you could import the components and use them as values in the designs object in place of strings.
let designs = {
"page1":Design1,
"page2":Design2,
"page3":Design1,
"page4":Design2
}
make one function that return react component..
getComponent = ({data, pageName}) => {
if(pageName === "page1") return <Desig1 />;
if(pageName === "page2") return <Design2 />;
}
and call function from render of DesignedPage component
const {page, data} = this.props;
return(
<div className="row flex-fill d-flex">
<div className="col-1">
{getComponent(page, data)}
</div>
</div>
)

Component is not reading object value from a const

I am trying to pass value from const options to a component. Am I doing everything right?When I try to read the props in child component I just get get value="undefined". I am just trying to pass options.value to FetchRandomBet in order to use options.value in a child component.
import React, { Component } from 'react';
import Select from 'react-select';
import Button from '#material-ui/core/Button';
import FetchRandomBet from "./fetchRandomBets";
const options = [
{ value: '1', label: 'less than 2' },
{ value: '2', label: 'more than 2' },
];
class Betslip extends Component {
state = {
names: [],
odds: []
};
render() {
return (
<div className="betslip">
<div className="betslip-top">
<h1 className="text">BETSLIP</h1>
<p className="text-two">BET WITH US!</p>
<Select className="filter-menu" options={options} />
</div>
<div>
<FetchRandomBet
key={options.value}
value={options.value} />
</div>
console.log(options.value)
<Button className="betnow" variant="contained">
Bet Now!
</Button>
</div>
);
}
}
export default Betslip;
options is an array of object, so you can't use options.value. You must go to the array element and then do .value on that, i.e., options[0].value, options[1].value.
It also depends on how FetchRandomBet component is accepting the props. If value props of FetchRandomBet is designed to accept array then, you just pass whole options like below code:
<div>
<FetchRandomBet key={1} value={options} />
</div>
Note: This is assuming your FetchRandomBet component accepts value as array.
Or if you want to call FetchRandomBet for each of the options value (which is highly unlikely with the context you provided in your question), you can do something like this:
<div>
{
options.map(option => <FetchRandomBet key={option.value} value={option.value} />)
}
</div>
The above code will create instances of FetchRandomBet for each of the option values.
First you should not console.log inside the return statement, but its okay outside.
Next try to use this
const value = options.map((op) => op.value)
const label = options.map((op) => op.label)
<FetchRandomBet
key={value}
value={label} />
You are acessing an array like if its an object so first you should enter the object and then select the key or the value.
In this way you will pass to the child component two array:
value = [1,2]
label = ["less than 2", "more than 2"]
Let me know if its what u were looking for

How to add places parameter in google map API URL to fetch specific type of location for auto-complete

I'm trying to implement a autocomplete search input bar for auto-completing the results of searching colleges and university in my React app.
my code is as per the following:
import React, { Component } from 'react'
import './App.css'
import PlacesAutocomplete from "react-places-autocomplete";
export class App extends Component {
constructor(props) {
super(props);
this.state = { address: '' };
}
handleChange = address => {
this.setState({ address });
};
render() {
return (
<div>
<PlacesAutocomplete
value={this.state.address}
onChange={this.handleChange}
onSelect={this.handleSelect}
// searchOptions={searchOptions}
shouldFetchSuggestions={this.state.address.length > 3}
>
{({ getInputProps, suggestions, getSuggestionItemProps, loading }) => (
<div >
<input maxLength="50" className="typo"{...getInputProps({ placeholder: "Search Your College" })} />
<div>
{loading ? <div>...loading</div> : null}
{suggestions.map(suggestion => {
const style = {
backgroundColor: suggestion.active ? "#41b6e6" : "",
};
return (
<div className="suggestion" {...getSuggestionItemProps(suggestion, { style })}>
{suggestion.description}
</div>
);
})}
</div>
</div>
)}
</PlacesAutocomplete>
</div>
)
}
}
export default App
and obviously the <script> tag in index.html
<script src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY&libraries=places"></script>
According to The gmaps docs, in order to only get selective results from these types: school,university,secondary-school and college I need to modify it. But, i clearly didn't got the docs correctly and wasn't able to understand it well.
so I wanted to know whats the correct way of formatting the url?
=> React-Places-Autocomplete docs
Note that what you're using is Place Autocomplete, not Place Search. The supported types for Autocomplete are listed in table 3:
geocode
address
establishment
(regions)
(cities)
So using other types like school won't work with Autocomplete; only with the Place Search service.
Hope this helps!

ReactJS - Difference between generates a unique id via default props and state

For some reason i need to generate some unique ID to use them as CSS ID Selectors in a ReactJs component , I've done two examples:
1) Defining a random value in default props, see Test with default props below
=>It doesn't work
2) Defining a random value in state see Test with state below
=>It works
Can some one explain why when i use default props i've got always the same value?
Codesanbox :
Codesanbox link with all code example
Source code :
function App() {
return (
<div className="App">
<h1>Components with random default props</h1>
<DymmyComponentProps />
<br />
<DymmyComponentProps />
<br />
<DymmyComponentProps />
<br />
<DymmyComponentProps />
<h1>Components with random state</h1>
<DymmyComponenState />
<br />
<DymmyComponenState />
<br />
<DymmyComponenState />
<br />
<DymmyComponenState />
</div>
);
}
Test with default props:
class DymmyComponentProps extends Component {
static defaultProps = {
id: `Unique id is: ${Math.random()
.toString(36)
.substring(7)}`
};
render() {
const { id } = this.props;
return <p id={id}>{id}</p>;
}
}
Test with state : (it work)
class DymmyComponenState extends Component {
state = {
id: `Unique id is: ${Math.random()
.toString(36)
.substring(7)}`
};
render() {
const { id } = this.state;
return <p id={id}>{id}</p>;
}
}
Can some one explain why when i use default props i've got always the same value?
As you can see, defaultProps is a static property
static defaultProps = {
...
};
Wich means it doesn't change on every new class, it's the same for every class.
And if you think about it, if the value is different on every instance of the class, it wouldn't be considered default, and in your case, it shouldn't be.

Passing Function Down [React]

I'm trying to pass down a function called handleDeleteToDoItem from the parent ToDoContainer to the child ToDoListOfItems.
This is done with <ToDoListOfItems toDoItems={this.state.toDoItems} deleteToDoItem={this.handleDeleteToDoItem} />
However, I'm getting an error that the function is never received by the child class when I reference it with this.props.deleteToDoItem when I'm rendering ToDoItems inside of ToDoListOfItems
All of the other states which I've passed down from ToDoContainer are being recognized, except for deleteToDoItem and I'm at a loss of what I've done wrong here. My IDE (Webstorm) is telling me the variable is unresolved.
Is there a different way I should be passing down functions from parent components to child components?
Thanks,
import React, {Component} from 'react';
import './App.css';
class ToDoContainer extends Component {
constructor(props) {
super(props);
this.state = {
toDoItems: [],
toDoWhat: ""
};
...
this.handleDeleteToDoItem = this.handleDeleteToDoItem.bind(this);
}
handleDeleteToDoItem(uniqueID) {
let updatedItemList = this.state.toDoItems.filter(toDo => {
return toDo.uniqueID !== uniqueID;
});
// Concat updated item list to blank array
this.setState({
toDoItems: [].concat(updatedItemList)
})
}
render() {
return (
<div>
<div>
<div>
<ToDoListOfItems toDoItems={this.state.toDoItems} deleteToDoItem={this.handleDeleteToDoItem} />
</div>
</div>
{/* TODO Create a form with a submit button to add items to the todolist */}
<form action="">
<div>
{/* Capture the value of the form input */}
<input type="text" onChange={this.handleChangeToDoItem} value={this.state.toDoWhat}/>
</div>
<div>
<button onClick={this.handleAddToDoItem}>Add Item to List</button>
</div>
</form>
</div>
);
}
}
// This is the container for all the indivdual items in the to-do list
class ToDoListOfItems extends Component {
render() {
//TODO Put in styling for the list of items
// Use map() to iterate through each item in the to-do list, creating new elements in the list container
return (
<ul>
{this.props.toDoItems.map(toDo => (
<ToDoItem key={toDo.uniqueID}
id={toDo.uniqueID}
toDoWhat={toDo.toDoWhat}
completed={toDo.isDone}
onDelete={this.props.deleteToDoItem}/>
))}
</ul>
)
}
}
Its a key name mismatch issue, because in ToDoItem you are passing the function by key onDelete not by deleteToDoItem:
Here:
<ToDoItem key={toDo.uniqueID}
id={toDo.uniqueID}
toDoWhat={toDo.toDoWhat}
completed={toDo.isDone}
onDelete={this.props.deleteToDoItem} // here
/>
So inside ToDoItem component it will be available by this.props.onDelete.
Suggestion: To avoid the confusion use key deleteToDoItem at all the places.
Try making the deleteToDoItem prop in the container class equal to an arrow function calling the handleDeleteToDoItem with parameters:
... deleteToDoItem={uniqueID => this.handleDeleteToDoItem(uniqueID)}
Also, using an arrow function in this way makes it so you don't need to explicitly bind the handler function. Make it into an arrow function (above) and it is automatically bound.

Resources