Dynamic Popover in ReactJS - reactjs

I'm fairly new to React and I'm using the Ant Design framework (https://ant.design/).
I have a table list of items that I'm looking to have a button on each so that when it is pressed additional information about that row becomes available (which is a secondary API call specific to that row).
I'm trying to use a popover but I'm noticing that the popover wants the text before being rendered which is a problem since I don't have that information until the second API call. The best idea I've come up so far is to have the button press trigger the api call and then the state is updated but that creates a funky experience (as it is update after the popover is already opened - after starting with the previous rows information). It isn't a huge amount of time but it still isn't an ideal experience.
This is what I have so far:
<Popover content={this.contentSec([record['section']])} title=
{record['section']} trigger="click">
<Button onClick={() => this.sectionAttributes(record['section'])}>
<Icon type="info-circle-o" />
</Button>
</Popover>
this.sectionAttributes triggers my fetch request. and this.contentSec does the formatting on the existing popup (see below).
contentSec(props) {
const listItems = this.state.attributes.map((item) =>
<li>{item}</li>
);
return <div><ul>{listItems}</ul></div>
}
Any ideas of a better way to handle this so that there isn't that buggy delay when clicking the button for the popover?
Thanks.

As the content is populated after the second api call, You can send two props content which can be empty string or any default value and loading variable as true on click. Once you have the data after the API call you can send the updated props ie content with actual text and loading as false and finally handle your logic and state update in componentwillrecieveprops() in the popover component.
You can use the loading prop to switch from a loader initially to the actual content.

Write a condition to check if the response from this.sectionAttributes(record['section'] is true, if it is true then
<Popover content={this.contentSec([record['section']])} title=
{record['section']} trigger="click">
<Button onClick={() => this.sectionAttributes(record['section'])}>
<Icon type="info-circle-o" />
</Button>
</Popover>
else simply use
<Button onClick={() => this.sectionAttributes(record['section'])}>
<Icon type="info-circle-o" />
</Button>
For the first time user clicks on button, the component rerenders and state gets updated, so when it rerenders you can see popover as the if condition satisfy.

Related

Refresh data from unrelated component React

I have a modal that is opened from an AppBar directly which let you insert data in the database.
On the current tab opened in background of modal, you can see a table with the current data, but the modal and the table aren't related. The page with the table is a route /Dashboard while the modal is just the modal, can be opened on front of any route.
I want that after you press the "Add" button in the modal to call the function that makes the get request on the /Dashboard route (which have the same named component).
I know about React Context but I that's all, I don't know exactly how to use it in this case after watching some tutorials.
This is my /Dashboard route:
const DashboardButton = (classes) => (
<Route render={({ history }) => (
<Button
className={classes.button}
onClick={() => { history.push('/Dashboard') }}
>
Dashboard
</Button>
)} />
)
which is in the same AppBar component as the modal.
Thank you for your time.
You might want to add an App level context provider and have a variable there, possibly a boolean or a status that the data should update on Dashboard when you add data from AppBar modal. I made a quick demo, check it out.
https://codesandbox.io/s/blue-dew-8rfho?file=/src/App.js

useState set method for modal not updating

I am trying to build a simple todo list. Basically there is a list of items. When the user clicks the 'edit' button on an item, selectedTodoItem is updated. Then a modal is shown which uses selectedTodoItem as prop.
I am also using ant.design library for the list.
Here is my code (with irrelevant bits left out):
const [selectedTodoItem, setSelectedTodoItem] = useState(selectedTodoList.items[0]);
const editItemHandler = (item) => {
setSelectedTodoItem(item);
dispatch(toggleEditTodoItemModalVisible());
}
return(
<List
className="whitebg listItems"
datasource={selectedTodoList.items}
renderItem={(item) => (
<TodoItemInList item={item} editHandler={editItemHandler} />
)}
/>
<TodoItemEditModal item={selectedTodoItem} />
);
<TodoItemInList> is basically a label and some buttons, one of which calls editHandler(item).
Here's a screenshot so you can get a better idea:
The problem is, when I load the page and click edit (blue, don't mind the delete icon) on an item, say 'Foundation', the edit modal loads fine. But when I click on another blue button, the modal still shows 'Foundation'. No matter what button I click, the modal only shows the first clicked item. It seems like selectedTodoItem is updating though, according to console.log(), but the modal's prop doesn't update with it.
Any nudge in the right direction would be much appreciated.

react limits the number of renders

in react I am displaying products I.E.
{renderPosts.map((item, index) => (
...
now, in each product, there is a button to delete that product, inside a button I have onclick that calls sweetAlert to delete particular product:
<Button
color="danger"
simple
justIcon
onClick={warningWithConfirmMessage}
>
Everything works fine like that... but if I want to pass ID of the product that has to be deleted...
<Button
color="danger"
simple
justIcon
onClick={warningWithConfirmMessage(item.postId)}
>
Now I am having error:
Too many re-renders. React limits the number of renders to prevent an infinite loop.
How I can pass anything to function... anybody
Thanks in advance!
The new onClick handler you're passing is calling the warningWithConfirmMessage every time it renders. To pass the function as a handler function instead of calling it, use:
onClick={() => warningWithConfirmMessage(item.postId)}

Update array of items with help of modal input in React

I didn't find any suitable answer for this question. Here is what I am looking for.
I have lists of menus items coming from the state array variable (https://i.imgur.com/FzD0sol.png).
I have an add button which opens a modal. Modal includes an input field. (https://i.imgur.com/6DCZhoj.png)
The final result would be when some click adds button of modal, its field values updated in menus state array. which further updates the menus list on UI.
I able to made all these UI. But I didn't have any idea how can I pass my data from modal input to menus list. Here is codesandebox link of the same problem (https://kx6yr.csb.app/).
There is a way to solve your problem :
You have to give a callback props to your Modal component. As it, The modal will be able to add an item.
There is the codesandBox : https://codesandbox.io/s/friendly-boyd-ptxem
So this is one way to do it, in your modals add this onAdd prop:
<AddModal
heading="Add Food"
modalId="addFood"
inputName="addFood"
onAdd={(textEntered) => { alert(textEntered); }}
ref={this.foodModal}
/>
<AddModal
heading="Add Drink"
modalId="addDrink"
inputName="addDrink"
onAdd={(textEntered) => { alert(textEntered); }}
ref={this.drinkModal}
/>
And within the modal component, call this handler passing the input value:
<button
type="button"
onClick={this.props.onAdd.bind(this, this.state.item)}
className="golden-button-op"
style={{ margin: "0px" }}
>
Add
</button>
Hope it helps!

Setting state in a subcomponent of react-table closes component resetting all states with ReactJS

I've been using react-table heavily throughout my React app which has been so useful but now I've got a weird bug I believe
I've got a react table with a subcomponent structured as such
<ReactTable
data={Data}
columns={columns}
SubComponent={row => {
return (
<div>
<p>I am the subcomponent</p>
<button onClick={this.toggleHidden.bind(this)} >
Click to additional information
</button>
{!this.state.isHidden && <p>Hello world</p>}
</div>
);
}}
/>
And here's what that looks like in the browser - the blue button on the left opens and closes the subcomponent and that works just fine, I've used subcomponents like this throughout my React App with no problems
When clicking the 'Click to additional information' button I want to show additional information ('Hello world' in this example) it runs this piece of code
constructor () {
super()
this.state = {
isHidden: true
}
}
toggleHidden () {
this.setState({
isHidden: !this.state.isHidden
})
}
But what happens in the browser is that the subcomponent toggle is closed and looks like this
If I reopen the subcomponent you can see that the 'hello world' is now showing so if did work as I wanted but just automatically closing the subcomponent which I didn't want to happen
In the console I'm not getting any errors or logs from react-table - it seems that any time I try to set a state inside of the react-table subcomponent that it will automatically close like this
My guess is that setting the state has reset all the states and that is what is confusing react-table, but I don't see how it would be?
I've just updated react-table to the latest version 6.8.6 but still have the same problem
Is this a bug or is there something I've done wrong here?
i fixed this by collapseOnDataChange: false
I had a similar issue. I have a subcomponent and inside the subcomponent are buttons which trigger functions when clicked:
The delete button had the following code:
<button id="delete" onClick={this.deleteClient('id')}>Delete</button>
where deleteClient is defined as:
deleteClient = (clientRef) => {
console.log(`deleting ${clientRef}`)
}
With the above code, "deleting id" would console.log both when I opened the subcomponent and when I clicked on the button.
I resolved the problem by using a callback in onClick as such:
<button id="delete" onClick={() => this.deleteClient('id')}>Delete</button>
Now "deleting id" only console.logs once, at the appropriate time, which is when I hit "Delete".
TL;DR:
set your onClick to a callback function.
Hope that helps!

Resources