I have a list of poem titles and images within article HTML tags. Whenever a user clicks on an article, I want a modal to show the poem verses. As of now whenever an article is clicked, the modals for every poem opens. How do I open the modals one at a time? This is my first time using React.
Link to my codesandbox:
https://codesandbox.io/s/and-air-52dpo?fontsize=14
You need to separate each Poem card to a component, and put the state inside them.
By using state on parent component as you did, it cause all poem card depend on same state.
I've forked your codesandbox, and fixed them. You can check it.
https://codesandbox.io/embed/and-air-543tl
You're using a single show variable in your Poems component.
This doesn't allow to show a single one of your modals, as all of them are referenced to this same variable.
I would use an integer in the Poems's state - rather than the boolean show - to store the currently presented modal.
The best option for this integer is probably the poem's index, as you should anyway add to your map function:
const listItems = data.map((poem, index) => (
<React.Fragment key={index}>
// The rest of your code is the same
<Modal
show={this.state.currentModal === index} // only this property was updated
onClose={this.showModal}
title={poem.title}
>
// modal code
</Modal>
</React.Fragment>
))
Related
I have a list of items like this:
<div className="items-section">
{items.map((item) =>
<Item key={item.id} {...item} />
)}
</div>
When user clicks on an item from the list, they will get redirected to /items/:itemId url to see that item, when they click to go back or close that modal that will display that item, I want to display the list and focus on the element where they stopped and clicked. How is it working now, 20 items are displayed to the user, they click on the 11th item, then click back and again list is displayed starting from the top page from 1st item. How can I make it to get back to that 11th element for a better experience?
I am using redux as well and I thought to keep track of the element clicked, but how to reflect this in React and display from that element. I thought of useRef but I do not see how to use here. Could anyone please suggest me what to do and how to achieve this?
You can give ids while you are mapping your list. Like this
{items.map(item => <div id={`foo-${item.id}`}>foo</div>
then whenever you want to select this item you can
const foundItem = document.getElementById(`foo-${here is your stored item.id in redux}`)
and now you have this node. If you want you can scroll to this node by using scrollTo or if you want give a class.
Context
Let's say I have page that displays a list of employees, along with many other buttons and components. and whenever I click on an employee, a side panel appears with a bunch of information about that employee. If I click on any other employee while an employee is selected, the side panel remains intact with only the information inside it being re-fetched and updated.
I can also, change the employee's information from that side panel by editing the different fields and clicking Update which bulk updates every updated fields.
Problem Statement
Whenever an employee's information is being edited, I can also click on another employee, which, of course, means that the edited data for the previous employee is lost.
Objective
What I need to do in this case is that, whenever an employee's information is being edited from the side panel (a flag is present to denote that), and if any other component/buttons apart from Update is clicked, then I need to show a modal which states that everything that is unsaved would be lost. If the user selects Ok, the component that was clicked should mount/rendered/perform whatever it does. Otherwise, the user should go back to the previous state.
I initially tried to achieve that by using componentWillUnmount of the sidepanel, but it didn't really work because that component will unmount anyway. What I am thinking is that, I need to put a onClick handler in every button/component now apart from that 'Update' which checks if any information is being edited, if yes it will render that component, if not it will render that modal, and the user decides what to do in that modal. I am very skeptic about this as well by placing checks everywhere for a minor thing.
Anyone with experience about related to this use case ? Any insights would be highly appreciated. :)
First Put isEdited state isEdited: false Then when you edit the post then set isEdited to true. When user clicks update then set isEdited back to false. When user clicks button other than update then check isEdited if isEdited is true then dispay modal with message and button when button of model is click set isEdited to false.
Hopefully this will help
There are a few ways I can think to do this.
Add a check at the start of the function for each buttons onClick. As you've mentioned already, this is tedious, especially if there are lots of buttons that should affect the state.
Create a function that wraps the onClick functions, to perform this check. Similar to 1, however a bit easier to repeat:
const myOnClick = newEmployeeNumber => {
myState.employeeToView = newEmployeeNumber;
}
const checkUserWantsToContinue = (onClickToRunWhenContinued) => {
if (myAppState.isEdited) {
promptUserToSaveFirst();
} else {
onClickToRunWhenContinued();
}
}
return (
<div onClick={checkUserWantsToContinue(myOnClick)} />
);
You mentioned that you are trying to put this into the componentWillUnmount function. That implies that something is making the component unmount. Can you add the check in there? So rather than checking with the user before the component unmounts, check with them before the action that makes the component unmount.
I've looked up whole google for my answer (haha).
What I am trying to achieve:
My fist screen is a form with some input fields which store the input to state.
By clicking "submit" the user comes to the next page/screen, where the previous input is supposed to show up. I want to show only the input data as a p-tag, not as an input tag anymore.
How do I achieve this? I am bloody new to reactjs.
I've thought about multiple solutions:
store the input data to an external JSON (which seems pretty complicated)
pass the data as props, but I am not aware of how I would do this
Thanks so far!
I'm going to assume that your second screen has the same parent component as your first, something like this:
render() {
return (
<div>
{this.state.showFirstScreen && <FirstScreen />}
{this.state.showSecondcreen && <Secondcreen />}
</div>
)
}
If that's the case, your FirstScreen component can accept a prop called something like onSubmit -- you say that you already store the input values from FirstScreen in state, so when FirstScreen is finished, you can call this.props.onSubmit(this.state) and it will send up the state to your parent component, as long as you've defined a callback function in the parent component:
{this.state.showFirstScreen && <FirstScreen onSubmit={this.onFirstScreenSubmit} />}
Then, you can save the state of the first screen into the state of your Parent component, and pass that part of the state down to SecondScreen
[edit] here's a very crude example: https://jsfiddle.net/df4s9ey8/
I have a component called PastIssues, which lists all of the past editions of a magazine. The output of the component is an ordered list where each item is the year of release followed by the season. For example:
Spring:2014
Autumn:2015
Each of these items is a Link that points to a specific path. I've dynamically added to this component, such that my ShowArticleInfo component will be displayed. My issue lies, when the user clicks one of the Links, my ShowArticleInfo component gets rendered, but only below ordered list. I would like my ordered list to disappear, such that the only remaining component is ShowArticleInfo.
So before the user clicks anything, I want a list of links, one for each article (in the example above). After a user clicks one of them, I want the list to disappear and only ShowArticleInfo to appear.
Is there an elegant way to do this?
Use local storage to set a key with value true
componentDidMount(){
localStorage.setItem('loaded','true');
}
and clear local storage when u unmount component ShowArticleInfo.
In your ordered list component render.
render(){
let loaded = localStorage.getItem('loaded');
return(
<div style={{display:{loaded ==='true' ? 'none':'block'}}>
</div>
)
}
For further info on localstorage MDN/localstorage.
I'm building a WYSIWYG tool in React/flux where you build interfaces by dragging and dropping elements onto a page. So for instance, I have a list of droppable elements: List, Form, Input Box, Text Box, etc. When the user drops one of those elements on the page, I need to insert the associated react component (and I store a name property of the object they drop, so I will know the component name I need). So if a user drops a list onto the page, and my associated component tag is <list />, I can't do just <{component.name} /> and it will turn it into <list />...yet I need a method of doing so. Any thoughts?
So fiddling around with this, I ended up getting it to work like this:
var Sort = require('./sort')
var List = require(./list')
var allComponents = {
sort: Sort,
list: List
}
React.createElement(allComponents[component.componentName], {data:component.data})
so now if my component.componentName is list, it will render the component, and data will become my properties