Pass an object value in props to another component - reactjs

Consider the code below, I need to pass an id which is in object format to another component by props. But I have try many time and it not working. I think I may have some thing mistake, but I'm not sure where is it.
Main page (updated):
render(props){
const data = this.state.data;
return (
<div>
<Header />
<NavigationBar />
<PurchaseInfoView show={this.state.displayModal} closeModal={this.closeModal} value={this.openModal}/>
<div className="purchase-side">
<div className="side-title">
<h1>Purchase Order List</h1>
</div>
<hr class="solid" />
{
Object.keys(data).map((key) =>
<div className="list-item">
<h2 onClick= {() => this.openModal(data[key].id)}> //get id
{ data[key].item_name}
</h2>
</div>
)}
</div>
<div className="dads">
</div>
</div>
);
}
openModal (Updated):
openModal = (id) => {
this.setState(
{
displayModal: true,
id: id
});
console.log(id) // i can get the id from here id=1
};
PurchaseInfoView to get the id (Updated).
class PurchaseInfoView extends Component {
render() {
console.log(this.props.id) // get undefined
return (
<div className="Modal"
style={{
transform: this.props.show ,
opacity: this.props.show ? "1" : "0"
}}
>
<h3>Purchase Order detail</h3>
<p>Id: {this.props.id}</p> //cannot get it
</div>
);
}
}
export default PurchaseInfoView;
console.log result:

If you want to pass an object to props here are the steps:
define the object in your parents state.
pass the object in props when calling components
get the object from props in child.
Here you are missing the second step!
You should try these:
MainPage
render(props){
const { data, modalObject, displayModal } = this.state; //use destructuring is more readable
return (
<div>
<Header />
<NavigationBar />
<PurchaseInfoView show={displayModal} closeModal={this.closeModal} modalObject={modalObject}/> //pass the object from destructuring state as props
<div className="purchase-side">
<div className="side-title">
<h1>Purchase Order List</h1>
</div>
<hr class="solid" />
{
Object.keys(data).map((key) =>
<div className="list-item">
<h2 onClick= {() => this.openModal(data[key].id)}> //get id
{ data[key].item_name}
</h2>
</div>
)}
</div>
<div className="dads">
</div>
</div>
);
}
OpenModal
openModal = (id) => {
this.setState(
{
displayModal: true,
modalObject: {id: id, ...any others key/val pair}
});
};
PurchaseInfoView
class PurchaseInfoView extends Component {
render() {
const { modalObject} = this.props; //here get your object from props
console.log(modalObject.id);// here you have the object
return (
<div className="Modal"
style={{
transform: this.props.show ,
opacity: this.props.show ? "1" : "0"
}}
>
<h3>Purchase Order detail</h3>
<p>Id: {modalObject.id}</p>
</div>
);
}
}
Tell me if you have any question in comment ;)
NB: i did this with an object (aka {} ) if you needed more things in your modal than just id. If just id is needed you just have to replace the modalObject by just the "id" you need
Cheers!
EDIT: for this solution to work you have to either:
initialise your state to this at least:
this.state={ modalObject : { id: ''}}
or make a not null test in your child component before displaying the element like so:
Id: {modalObject && modalObject.id ? modalObject.id : ' '}
These are needed because on first render your state will have the initial state you setted so if you didnt set anythin or didnt test for a value... well... it's undefined! :)
(note if id is null instead of having an undefined error you will have a blank space displaying in your modal)

Guess you are calling it wrongly. It should be {this.props.id}
render() {
console.log(this.props.id);
return (
<div className="Modal">
<h3>Purchase Order detail</h3>
<p>Id: {this.props.id}</p> //Changed line
</div>
);
}
Inside main page pass the id to PurchaseInfoView and access it as a prop
<PurchaseInfoView show={this.state.displayModal} closeModal={this.closeModal} value={this.openModal} id={this.state.id}/>

Related

how can I add any event to a specific part of component ? react

I have list of data that render it with map - I need to add an event just in one of the item from that list.
const UserModal = (props) => {
const {user,setUser} = props ;
const list = [,{id:3,text:'گفت وگو ها',icon:<BsChat />},{id:5,text:'خروج',icon:<BiExit />},];
/this is my list for making navigation bar
return (
<div className={style.main}>
<div style={{bordeBottom:'1px solid black'}}>
<BiUser />
<p>{user.username}</p>
</div>
{ //this is where I render a list to show and make component
list.map((item)=>
<div key={item.id}>
{item.icon}
<p>{item.text}</p>
</div>)
}
</div>
);
};
export default UserModal;
this my code and for example I need to add an event on specific object that has id=5 in that list .
how can I do that
I don't know if there is some sort of built-in solution for this, but here is a simple workaround:
I changed a few things for simplicity's sake
The important part is the if statement with checks if item ID is 5 then if so adds a div with the desired event
function App() {
const list = [
,
{ id: 3, text: "comonent 3" },
{ id: 5, text: "comonent 5 (target)" }
];
return (
<>
<h1>Hello world<h1/>
{list.map((item) => (
<div key={item.id} style={{ backgroundColor: "red" }}>
<p>{item.text}</p>
{item.id == 5 ? (
<div
onClick={() => {
alert("This component has a event");
}}
>
{" "}
event
</div>
) : (
<></>
)}
</div>
))}
</>
);
}
const UserModal = (props) => {
const {user,setUser} = props ;
const myEvent = () => alert('event fired');
const list = [,{id:3,text:'گفت وگو ها',icon:<BsChat /> , event : myEvent},{id:5,text:'خروج',icon:<BiExit />},];
/this is my list for making navigation bar
return (
<div className={style.main}>
<div style={{bordeBottom:'1px solid black'}}>
<BiUser />
<p>{user.username}</p>
</div>
{ //this is where I render a list to show and make component
list.map((item)=>
<div key={item.id}>
{item.icon}
<p onClick={item.event}>{item.text}</p>
</div>)
}
</div>
);
};
export default UserModal;
list.map((item, i)=> (
item.id == 5 ?
<div onClick={handleClick} key={i}></div>
:
<div key={i}></div>
)

How on click rerender conmponent in react

When I click on a card, the loadAboutInfo function works through which I transfer data to another component and display it there. But if I click again on the same card, then it is duplicated. How can I fix it?I have check which take card id and then if it the same it render but I click again it render one more card, but i need if it already exist than new card mustn't render
loadAboutInfo=(pokemonValue,pockemonImg,pokemonId)=>{
this.setState(prevState => ({
pokemonValue:[...prevState.pokemonValue, pokemonValue],
pockemonImg,
pokemonId
}))
}
render() {
return (
<div className="wrapper">
<div className="pokemonlist__inner__cards">
<div className="pokemonlist__cards">
{this.state.pokemonList.map((value,index)=>{
let pokemonImgTemplate = this.state.pokemonImgTemplate;
let pokemonId = value.id;
let pockemonImg = pokemonImgTemplate.replace('{id}',pokemonId);
return(
<div className="pokemonListCard" key={index} onClick={()=>this.loadAboutInfo(value,pockemonImg,pokemonId)}>
<PokemonCard
pockemonImg={pockemonImg}
pokemonName={value.name}
pokemonTypes={value.types}
/>
</div>
)
})}
</div>
<PokemonLoadMore
loadMore={this.loadMore}
currentPage={this.state.currentPage}
/>
</div>
</div>
);
}
}
component where i map get data
render() {
return (
<div className="pokemon__about">
{this.props.pokemonValue.map((value,index)=>{
let totalMoves = value.moves.length;
return(
<div className="pokemon__about__wrapper" key={index}>
{this.props.pokemonId == value.id ?
<div className="pokemon__about__inner" key={index}>
<AboutImage
pockemonImg={this.props.pockemonImg}
/>
<AboutName
pockemonName={value.name}
/>
<div className="pokemon__about__table">
<AboutPokemonTypes
pokemonTypes={value.types}
/>
<table>
<AboutPokemonWeight
pockemonWeight={value.weight}
/>
<AboutPokemonMoves
totalMoves={totalMoves}
/>
</table>
</div>
</div>
:
null
}
</div>
)
})}
</div>
);
On the loadAboutInfo you can check if there is already a pokemon with the same id on pokemonValue array, something like this:
loadAboutInfo = (pokemonValue,pockemonImg,pokemonId) => {
// this will get the first element that matches the id
const exists = this.state.pokemonValue.find(pokemon => pokemon.id === pokemonId)
if (!exists) {
this.setState(prevState => ({
pokemonValue:[...prevState.pokemonValue, pokemonValue],
pockemonImg,
pokemonId
}))
}
}
So it will update the state only if the clicked pokemon isn't in the pokemonValue array

ReactJS Conditional rendering is not working

I have an input and whenever a user clicks in the box I want to see if the input is greater than 1
updateQuery(e) {
this.setState({ query: e.target.value });
const optionValue = e.target.value.length;
}
Then I want to do the following in render / return:
render() {
const { query } = this.state;
return (
<div>
{optionValue > 1 ? (
<div className="loading">
) : (
<div className="not-loading">
)}
<NewSearch query={query} updateQuery={this.updateQuery} />
</div>
<Debounce ms={1000}>
<BusInfo query={query} />
</Debounce>
</div>
);
}
But I get this issue:
Line 48:6: Parsing error: Unexpected token ;
and my app won't run.
What am I missing here?
I've read this doc:
https://reactjs.org/docs/conditional-rendering.html
Help!
It seems that the only thing you need to change based a certain value of optionValue is the className of the div.
Hence, you can do something like this:
return (
<div>
<div className={optionValue > 1 ? 'loading' : 'not-loading'}>
<NewSearch query={query} updateQuery={this.updateQuery} />
</div>
<Debounce ms={1000}>
<BusInfo query={query} />
</Debounce>
</div>
);
Also, optionValue is a const of updateQuery and cannot be accessed later on your render. You should also add optionValue on your state:
updateQuery(e) {
this.setState({
query: e.target.value,
optionValue: e.target.value.length
});
}
And later on your render:
const { query, optionValue } = this.state;
or just check on your render query.length instead of holding a new value just for this on your state.
In case you have classes that you want to share on both cases, you could use template literals to achieve this:
<div className={`myClass1 myClass2 ${optionValue > 1 ? 'loading' : 'not-loading'}`}>
Don't define html tag like react component
Change this
{optionValue > 1 ? (
<div className="loading">True condition</div>
) : (
<div className="not-loading">False condition</div>
)}
Your opening and closing tags don't match up, you have an unmatched closing </div>
If the conditionally rendered divs don't have any content, that's fine but they do need to be self-closing: <div className="loading" /> (note the closing />)
This should now work fine (although you may need to do this.optionValue)
updateQuery(e) {
this.setState({ query: e.target.value });
this.optionValue = e.target.value.length;
}
render() {
const { query } = this.state;
return (
<div>
<div>
{this.optionValue > 1 ? (
<div className="loading" />
) : (
<div className="not-loading" />
)}
<NewSearch query={query} updateQuery={this.updateQuery} />
</div>
<Debounce ms={1000}>
<BusInfo query={query} />
</Debounce>
</div>
);
}

Accesing object using props in ReactJs

I'm trying to access object keys using props as an index but it's not working. Error: Objects are not valid as a React child (found: object with keys {id, name, img_url, location}). If you meant to render a collection of children, use an array instead.
I am new to React so I appreciate any help.
My code:
class ExpandCard extends React.Component {
render() {
const props = this.props;
const profiles = props.profiles;
return(
<>
<div className="">
{profiles[props.active]}
</div>
</>
);
}
}
class App extends React.Component {
state = {
profiles: testData,
active: null,
}
getActive = (dataFromCard) => {
console.log('the magic number is', dataFromCard);
this.setState({active: dataFromCard});
}
render() {
return (
<div>
<div className="wrapper">
<header>
<div className="logo">LOGO</div>
</header>
<Form />
<div className="cards">
<div className="card-list">
{this.state.profiles.map(profile => <Card key={profile.id} {...profile} activeCard={this.getActive} />)}
</div>
<div className="expand-card">
<ExpandCard active={this.state.active} profiles={this.state.profiles} />
</div>
</div>
</div>
</div>
);
}
}
It looks like {profiles[props.active]} returns an object that looks like this:
{ id, name, img_url, location }
You can't return an object from a React component, maybe you meant to return {profiles[props.active].name}?

Warning on empty prop: why it happens?

I have component, which needs to fetch server data before rendering:
class BooksManage extends Component {
componentWillMount () {
const { dispatch, fetchManagePage } = this.props
dispatch(fetchManagePage())
}
render () {
const sections = this.props.books.map((section, index) => {
return (
<div className='row' key={index}>
<BookSectionContainer index={index} />
</div>
)
})
return (
<div className='row'>
<div className='col-md-8'>
{sections}
<BookPaginationContainer paginationClass='books' />
</div>
<div className='col-md-3'>
<div style={{position: 'fixed', width: 'inherit'}}>
<EmployeesListContainer />
</div>
</div>
</div>)
}
}
As you can see, it uses BookPaginationContainer, which expects several state parameters:
Warning: Failed prop type: The prop `currentPage` is marked as required in `Paginate`, but its value is `undefined`.
Etc.
Problem: as BookPaginationContainer is child of BooksManage, what I expect to achieve with componentWillMount() is that dispatching an action fetches state parameters which needed.
What actually happens:
action REQUEST_MANAGE_PAGE # 18:41:49.770
Warning: Failed prop type: The prop `currentPage` is marked as required in `Paginate`, but its value is `undefined`.
action RECEIVE_MANAGE_PAGE # 19:01:40.327
After all page renders correctly, but I'm concerned with how good is this.
Don't render components that need data until you have that data.
render() {
...
if(!this.props.requireData) {
return <div>Loading</div>;
}
return (
<div className='row'>
...

Resources