How to select items in app and updating the state in react - reactjs

I want to build a simple app like in picture attached with react js, I just cannot find the right idea of:
How to "select" photos(or item) in an application and have the "cart"-like component appear at the bottom when at least one photo/item is selected(and close and deselect all already selected photo/items) and expand the cart-like component at the bottom when clicked to show what's been already selected.
What is the best approach to this?
P.S I'm new to react with a big idea in mind xD
app's view

This question definitely needs more information, but I will try to point you in the right direction. There are hundred of ways to create the UI/functionality you are describing but here is a very generic overview;
The "items" (Img1-6) looks like a grid of ShopItem components, possibly in a CSS Grid / flexbox. Each ShopItem would probably make use of an onClick method to "do something" when it is clicked - this may involve updating a state (using the useState react hook) somewhere which tells you if a ShopItem is checked or not. It could also potentially use a callback method to do something in the parent when the items are checked.
I imagine that each ShopItem may own its own "checked" state or may update a global state (Such as Zustand or Redux) or a Context (React) when it is toggled on and off. The checked state of a ShopItem would also inform the UI of the component.
The "cart-like" component could be looking at the global state/context/callback from the item component, and could change based on its value and how many checked items there are. (Eg/ checkedItems !== 0 ? show : don't show)
This is just one way in which this UI can be built, if you would like a more specific solution, please edit your question to include code snippets and what you've already tried.

Related

React & Canvas: changing state is breaking Canvas functions

I am trying to use a parent component to control animations in a child Canvas element. Specifically I want an animation to happen when a user inputs a correct answer.
It works until the user changes the state in the parent component, and then it no longer works.
I've made a stripped-back, minimal version of my code here to show my issue: https://codesandbox.io/s/epic-leaf-08jqvy?file=/src/App.js
My desired behaviour is that the red box bounces when a user clicks submit. That happens if they don't type anything in the input box, but as soon as you enter anything into there - changing state and re-rendering the component - the button no longer triggers the animation in the Canvas child component.
As far as I can tell, the issue is to do with changing the state when inputing text. If I make a version where the input is just assigned to a variable, it works fine, but I need to be able to use state and re-render other parts of it.
I have put a console.log in the jump() function, so I can see that it is being called, but no animation is taking place in the canvas.
I assume that what's happening is that everything is being re-rendered when the state changes, and so the useRef is no longer tracking to the right thing.
Things I've tried:
putting the canvas in a memoized component to prevent it from re-rendering
using eventlisteners to see if I can trigger the animations in other ways - keydown ones work, but I need the user to be able to type, so I tried other ones (like hashchange or audio.play) but neither of those worked.
You can see the thing I'm actually trying to build here: https://papaya-platypus-86565f.netlify.app/play Basically users answer questions and an animation plays depending on whether they're right or wrong, to give it a game-y feel.
Thanks!
I like your red box as well as your reasoning. Yes, the input state changing on keystroke is causing the entire App component to re-render. Note that your App.js component has a lot going on (all good stuff), such as your Box class instantiation, your canvas instantiation, etc.
The key is to break your components into smaller parts, particularly separating stateful components from non-stateful components. We don't want your canvas re-mounting on every input change, so we make them sibling components!
Here's a working example of your code, just in smaller components:
https://codesandbox.io/s/strange-julien-d3n4zm
I hope this helps.

React-leaflet performance issue, prevent GeoJSON re-render

I have the following issue:
I would like to create a simple choropleth map using react-leaflet's GeoJSON component. I also want to have a tooltip that shows a value on hover over a GeoJSON feature. The problem is performance. A CodePen example can be found here: https://codepen.io/timester-the-typescripter/pen/gOXGKOY
I attach event handlers to each GeoJSON feature and set a state variable in my "main" component that holds the value for the currently hovered area.
const [selected, setSelected] = React.useState(null);
My tooltip relies on that state variable to show its value. Because every mouse hover event causes main component state change, the GeoJSON component gets re-rendered all the time. This is not a huge problem in the CodePen example, but for a full world map it is unfortunately.
I assume that the state change causes this because if I comment out the 2 setSelected lines (line 55, and line 67 in CodePen), the re-renders (calls to createGeoJSON ) stop, and the event handlers run a lot faster as the profiler pictures show below.
Mouseout event with state change:
Mouseout event with state change commented out:
I tried many solutions with no success. For example I think I can't memoize the GeoJSON component because the Tooltip must be its child and that depends on the state of the main component.
In the future I want to add more components depending on the hovered state variable like a legend, etc.. and maybe that variable will be a bit more complex than a simple number too.
What options do I have here? I had another stackowerflow question about this, but then I did not understand the problem completely, so it was not super focused. I'm at the point where I'm thinking about rewriting it in Angular. I found react and react-leaflet very pleasant to work with, until this issue came up.
The problem is that currently you are recreating the map with the appropriate Tooltip on each mouseover via the state. Instead, you should bind all Tooltips at map creation with layer.bindTooltip(). This will allow you to just show/hide them without having to recreate the map again, since they are already created and their creation will not rely on state.
See this github issue for an example with Popups (but the logic for Tooltips should be the same): https://github.com/PaulLeCam/react-leaflet/issues/33
I got help from this reddit comment https://www.reddit.com/r/reactjs/comments/std46f/comment/hx3yq34/?utm_source=share&utm_medium=web2x&context=3
The solution I applied based on this is not to use the Tooltip as a child component, but bind a tooltip to each layer in the onEachFeature method.
const onEachFeature = useCallback((feature, layer) => {
layer.bindTooltip(feature.properties.COUNT, {sticky: true});
...
This way I could also wrap the GeoJSON component in a useMemo() as there were no longer dependencies on the selected state. I also wrapped the style and onEachFeature functions in useCallback().
This combination solved the issue!

The Boundaries of UI State and Application State

I have trouble coming up or finding the boundaries of the so called "UI State".
Imagine the example of an issue tracker:
We have a list of "issue cards", which each contain:
A simple icon that represents the progress (i.e. open, closed)
The description text of the issue (a simple <p/> element)
A single Action button that changes d =epending on the state of the issue: "Assign to myself" or "Mark as done".
A button that opens a context menu (AKA right-click menu). This menu has a list of a variety of action buttons. Depending on the
state, some actions are greyed out and can not be clicked / or are
just not shown. Like "Close Case", if the case is already closed.
If you could categorize each of these items into UI-State vs. Application State, it would help me understand the boundaries.
More practically: How would you divide this little example application into containers and presentational components?
My interpretation: 1. and 2. are just presentational, 3. and 4. are stateful. Is this right? How would I structure this as containers and components?
Thank you very much!
All of listed examples are examples of application state, where UI is determined by persistent data that is received from the backend.
UI state usually refers to UI component local state that is determined by user actions, e.g. window position, active tab, unsubmitted form values, etc. Depending on the case, UI state may be lifted up and stored somewhere (persistent storage or URL) or be discarded.
if I want to implement this project I would act like this :
a component for managing all children components
a store to managing model, data and fields
a component for displaying icon and description text and button
a component for context menu
please consider that if you are using MVVM pattern, be sure that all responsibilities of actions are done by store and for changing some properties use observable fields
and if not use state in manager component and pass via proprs in children.

React Redux Components Communication Pattern

I am looking for a good code pattern to allow some communication between components, when using React & Redux.
Most likely this communication should be done via redux, like many articles suggest. (like this one, for example).
However, there are some situations when using the store would be a bit of a hack rather then using it for state management. These special cases are usually when you need to give a command to a component, like show or hide.
I will give an example:
Lets say that we have a <Tooltip /> component which all it does is render some help icon, that when clicked, opens a tooltip popup.
And lets say that we have more than one in a page, but we want to make sure that only one is open at a given time. So if tooltip A is open, and the user clicks on tooltip B, then B should open and A should close.
Here are some patterns that I thought might be relevant to implement this requirement:
Using Redux: We could have in the store some state for these tooltips:
{
showTooltip: "A" // the ID of the tooltip to show
}
This means that we have to connect the tooltips to the redux store, and check for each tooltip if it's ID is the one that should be opened, and when the user clicks on the tooltip icon, we dispatch an action to set the opened tooltip.
Using additional event mechanism: We can use an additional event mechanism to Redux, like emitter.
In this case we can fire an event whenever a tooltip is about to be opened, and all other tooltips can listen and hide themselves once they get such an event.
I have to say that it seems to me that maybe having two event mechanisms in the app seems a bit redundant, but on the other hand, using redux store to communicate with components seems a bit overkill.
Would love to hear some opinions about this issue.
The React and Redux world generally encourages representing your app's behavior as state. For example, rather than an imperative $("#someModal").show() command, you might save a flag value somewhere that says {modalVisible : true}.
There's numerous examples of using state to drive modals and popups. A typical implementation would store the values for a single modal or a list of modals in state somewhere (either in a parent component or in Redux), and then render modal components as appropriate based on those values, such as: {type : "notificationPopup", level : "warning", message : "Something happened!"}. The basic approach works whether you're storing the data in React, Redux, MobX, or something else.
For specific examples, see Dan Abramov's answer to "How can I display a modal dialog in Redux?", Dave Ceddia's article "Modal Dialogs in React", the article "Scalable Modals with React and Redux". I also have other articles that demonstrate modal management in the React Component Patterns#Modal Dialogs and Redux Techniques#UI and Widget Implementations sections of my React/Redux links list.

Flux: Handling Modal windows

How should Modal window be shown while using the Flux implementation. I can have the Component update its state to display a modal and close it once done. A save in the modal would trigger a action and update the store. But the modal would not that it needs to be closed. I would then need to emit a different event or have the store store the state of the modal.
For me it is perfectly fine to store the state of the modal in the store. On save event, just use a boolean value to say whether or not the modal should be displayed.
Your store doesn't need to have a single attribute, it can be more complex. Like having an array and a boolean.
When the save happens, just update your array and put a boolean open=false that you will use in your render method to not render the modal anymore. You don't need 2 actions to do that, one action can update your store model + update the boolean to false.
The complexity here is to know what to put in stores. How to organise your state... This can become quite complex over time. Until now I have found great success by using autonomous components, with their own stores, like widgets. You can find more details here.
In a more general way, you can put layout properties in stores. Like cursor or mouse position, opened modals, whether mouse is over some element or not...

Resources