Wrapping React Component Generically - reactjs

I've posted this on Reactiflux but may get more traction here. I've created a sandbox to demonstrate my need: https://codesandbox.io/s/xvnk0znw7z
What I'm trying to do is create a generic modal wrapper that I can use to encapsulate several components; in the sandbox, the component is a date range picker, but I also have a formik component for example.
The thing is, the Apply and Clear buttons need to be a part of the wrapping modal, and not the child component it wraps.
However, when clicking on Apply or Clear, saving the child component state to the Context (not included for brevity) is really the responsibility of the child component itself; only it knows how it should do it.
In the example above, that would be the ok and clear methods of DatesPicker. Intuitively, I would call children.ok and children.clear from the wrapping modal, but I know for a fact that's not how it should be done.
I looked a lot at the Cat and Mouse render-prop example in React's docs, but I can't get my head around how I can apply this here.

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.

Hook re-render whole page on single change in a sub component

I create 2 Text Boxes one with hook and the another one with the old style, now in Hook mode when the user input change the textbox value the whole page rendered, but with old style there only the text-box rendered not the whole page, if you have the complex page with many objects like (Data Table, form, buttons, inputs, etc..) the single change on one of these components forced to re-render everything and it decease performance, for example typing in the text-box take time to effect on page and the delay time is more than user typing speed.
the one workaround solution is using the callbacks and useMem but if the page is complex(lots of objects as described, and all of these objects has many properties the callback and useMem is very very complicated to handle single object property.
SandBox Example
This is exactly how react hooks should work. what will cause a rerender in react? two things:
change in props
change in hooks or say in a better way hooks state
in the second case, the useInput state is changing so that causes a rerender and it's absolutely normal behavior. I think using custom hook in that way is not a good practice.
I recommend reading this article for more information on react rendering: https://www.codebeast.dev/usestate-vs-useref-re-render-or-not/

Atomic Design, is a modal an organism?

There is a tile (molecule) with an image, some text and a play button. When the button is triggered a video should be shown via a modal. I think a modal should be an organism, but i want the modal to be part of the tile, which is an molecule.
The modal should be part of the tile, because its easier to use it that way.
I dont want always wire them up from inside an other organism, template or view.
Should i make the modal to a moclecule or should i make the tile to an organism?
Any advice?
I know this is an old question, but I recently stumbled on this while trying to figure out basically the same thing and wanted to add my two cents.
Note: I just started learning about atomic design, so this could be completely wrong - Take it for what it is, an opinion.
Brief background
In my case, I have a component (lets call it Form A) which is going to live inside of Modal A. Modal A is a very simple modal which is more of just a dialog modal (basically just contains open/close functionality) but it happens to have a form inside of it in this case.
Since the Modal technically contains a form (molecule) visually, I initially figured this must be considered an organism, or at the very least, another molecule.
My Solution
After thinking on this for a while, and referring to https://atomicdesign.bradfrost.com/chapter-2/ for guidance, in my instance the following sentence made it clear for me. (in my opinion)
These atoms include basic HTML elements like form labels, inputs, buttons, and others that can’t be broken down any further without ceasing to be functional."
In my mind, going by this logic, I can break my modal down all the way to the atomic level...
If I remove the Form A component from the modal content, the modal is still functional (just has no content). To me, this tells me that I should in fact make a general Modal component and label it as an atom.
After I have a Modal atom component, I can simply pass it children to change the content of the modal. This allows me to easily have a Modal A, Modal B, Modal C component which in my opinion would then be an organism since at that point it is implementing the molecules to create a larger component.
Possible Answer?
So, if I were going to try to answer your question while using my own logic:
I would personally create a simple general re-usable modal component as an atom, then I would create an organism, say <PlayVideo /> which has inside of it the
<Modal props={modalSpecificProps}>
<Video />
{any other content to display in the modal}
</Modal>
With <Video /> being a child along with whatever else should be displayed inside the modal.
The only thing I would say I'm still unsure about myself is, can something be an atom, but still technically allow children to be placed in the atom as well?
Anyways, food for thought for anyone else that stumbles across this.

Communication between nested but independent components in react.js

i like to develop a simple tooltip component in react.js
the tooltip gets defined like so in e.g. App.jsx:
<TooltipLink>Hover over me
<Tooltip>I am the Tooltip content</Tooltip>
</TooltipLink>
My question is: What is the best way of TooltipLink and Tooltip to talk to each other?
They are nested but I cannot use props because they are not nested directly in the component itself. Also, I don't want to use the parent (e.g. App.jsx) to manage the communication between TooltipLink and Tooltip because I want them to be self-contained.
I thought about refs but when i define a ref inside the Tooltip component then TooltipLink does not know about it (I assume because refs only work when components are nested inside the components themselves).
I could of course use simple DOM-programming for TooltipLink and Tooltip to communicate (e.g. use e.target when the user hovers over TooltipLink and then find its first child) but I thought there must be a more react-y way...
You have 3 options:
cascading props in the whole hierarchy
using redux
using the context API
I prefer to use redux, because the context API is not officially supported (breaking changes may happen, like in react 16.3). Cascading props is not really beautiful but may be convenient for small apps. (<MyComponent {...props}>)

How to pass prop to sibling in React?

I've designed a pretty simple responsive layout (be sure to open link with Chrome) and now I'm trying to implement it in React. I've attached some screenshots of the layout as well.
This app is supposed to be the typical tab/nav app, but due to the responsive layout, the view hierarchy is pretty awkward to work with in React.
I've built a React component called Layout to abstract away all the layout stuff. Layout also has props for renderLeft, renderRight, title, and onTab. Layout's children are then rendered into the content block.
The easy solution would be to make Layout a child of the current view and render whatever you want. However, this is going to mess up some animations I had in mind. I want to have a CSSTransitionGroup element wrapped around the tabbar, the title, and the left and right buttons animating them as they change. Thus, the Layout element must remain the same between the views else a new CSSTransitionGroup element will be rendered for each view which isn't good.
So now the problem is that I have a Layout component with a view rendered as its child (but sort of as sibling with respect to the App component), but the view needs to specify renderLeft, renderRight and title for the Layout which is its parent! For example, in the top-level App component, the render function may look like the following, and I need some way of setting Layout's renderLeft from the View.
render() {
return (
<Layout renderLeft={??}>
<View setRenderLeft={??}/>
<Layout/>
)
}
The only thing I've thought of so far seems totally like the wrong way of doing it:
In the top-level App component, have a state variables for renderLeft, renderRight, and title and App passes those to the Layout props. Now for the view, pass some functions like setRenderLeft, setRenderRight, and setTitle which will change the App state and thus change the Layout. We can thus call these functions in componentWillMount for each view.
This just seems like a total hack and seems to break the whole idea of one-directional-data-flow. However, I'm not sure how else to do it! Are there any more proper ways of doing this? I'm reminded of the concept of delegation when building iOS apps, but thats very OOP and not very FP.
Any ideas?
Your question is a little difficult to tell exactly what the issue is, however if I were you I would read up on https://facebook.github.io/react/tips/communicate-between-components.html
For communication between two components that don't have a
parent-child relationship, you can set up your own global event
system. Subscribe to events in componentDidMount(), unsubscribe in
componentWillUnmount(), and call setState() when you receive an event.
Flux pattern is one of the possible ways to arrange this.
You want to either have the siblings talk to the parent and communicate there, or at the global level.
Hope this helps.

Resources