I'm working on my first react app. I noticed that the state that contributes to an element is occasionally reflected in the reactid. Maybe it's the key that was passed?
I can't find a lot of documentation on reactid but I was wondering if there was a good way to isolate those keys.
for example, an element that I'd like to update has the ID: .0.1.0.1.$4.3:$level.1
The $ represent known indices of the state object I used to build that DOM node. (specifically, this is the object this.state.figures[4].level)
It would be really awesome if I could parse those $ values out with a predefined method, to make it easy to setState. Does such a thing exist?
This is me trying to setState on events defined by the top ancestor to avoid cumbersome bidirectional event handling. Am I being really foolish with my approach?
if I understand correctly you're looking to bind events to DOM nodes based on their data-reactid's?
If so - I don't think that's a wise idea at all. The data-reactid property is qutie transient, it changes without warning and is influenced by a number of events in the React ecosystem.
I like to think of DOM generated by React as a compile target, something I'm not really even supposed to interact with at all. A black box, if you will.
If you need help solving an eventing issue, you may want to describe that itself.
EDIT
You can add event handlers in React which are aware of their position in an iterator, and aware of the current state of the component.
<div>
{
things.map((thing, index) => {
return (
<li
className="level"
key={`level_${index}`}
onClick={this.handleClick.bind(this, thing)}>
{ thing }
</li>
);
});
}
</div>
So handleClick would receive the thing item when clicked, which could give you information about that particular thing. You could pass the index too. In handleClick you'll also have access to this.state.
Related
I've been reading about the advantages of using Context in React and I am unconvinced. I'm wondering if there's something I've missed.
Context provides a way to pass data through the component tree without having to pass props down manually at every level.
What's the hassle in creating a props object in the main component and just passing it around among the underlings? Something like:
// do this once at top level (I'm assuming [foo, foo_set] and [bar, bar_set] are state variables):
const props = {foo, foo_set, bar, bar_set, thisAndThat, theOther, whatever, etcAndEtc}
// including one component
<MyComponent1 {...props } />
// including another
<MyComponent2 {...props } />
(Maybe better to use another name than props for this object, as the components can have other properties. Anyway.)
Then in MyComponent1 you can access all the props you want, or not access them. Either:
...
const MyComponent1 = (props) => {
...
// here we can use any props we need, props.bar, props.bar_set, props.theOther for example
const localVar = props.bar * 2;
props.bar_set(localVar);
// this changes the value of bar throughout the app
...
}
the advantage of the above, as I see it, is that you can pass around the props object to other sub-sub-components and not worry about whether you have anything missing.
Or:
...
const MyComponent1 = ({bar, bar_set, theOther }) => {
...
// here we can use bar, bar_set, theOther in the same example
const localVar = bar * 2;
bar_set(localVar);
...
}
The advantage of this option being that the syntax is shorter.
So my point is why not just use the standard JavaScript syntax? Why introduce new concepts when there are plenty to assimilate to do all sorts of other things?
Consider a fairly common case for most applications: You have authentication information (eg, the current user), a routing library (eg, react-router), and a theme object (what colors to use). These are needed in components scattered throughout the app.
You want to render a button somewhere down at the tip of the component tree. It's going to show the user's avatar, so it needs the authentication data. It's going to navigate when clicked, so it needs the navigate function from the routing library. And it needs to style itself according to the theme.
This certainly can be done through props, but in order for the button to get the props, every component in the chain above it must get and forward those props too. This could be many components deep, like page component -> section component -> table -> row -> widget -> button, and most of them don't need that information for themselves, so they're just taking the props in order to forward it along.
And you can easily imagine cases where there are more than 3 pieces of data that are needed across the app.
What's the hassle
Most people find this "prop drilling" to be a hassle, but let's assume you don't. You still have the problem that it has bad performance. If every component must receive the full set of "global" values that the app might need, then any time anything changes, the entire app must rerender. Optimizations like react.memo become effectively useless. You will get much better performance if you only pass the props you need.
Easier to edit code (You don't have to delete for example unused variable)
Better redability (You dont see unnescesary variables, and You see which component is using variables)
Lesser performance waste (preventing from consuming unnescesarry variables)
Suppose You got 10 descendants in - You would have to pass one variable through 10 of components.
What if some could have the same variable name ? You would have to edit Your passed variable for a while, then edit back later.
To sum up:
Using Context more efficient than stuffing everything into a single object variable, because it avoids re-rendering the whole app when anything changes.
People think passing a single variable around is more hassle than introducing specific syntax.
Context also allows you to have different values for the same variable in different parts of the app. This is shown here (the best explanation IMHO) : https://beta.reactjs.org/learn/passing-data-deeply-with-context
The above article also specifies that sometimes passing props is the best solution. It gives a list of use cases for context, and the advantages provided in each case.
I'm trying to find a good way to produce a layout control that wraps all it's DOM children, let's say in a div tag for simplicity. The basic approach is to use React.Children.map, but this is posing some problems with constructed lists of children via components -- it cannot see inside Components.
For example, say I have this structure, where the final DOM result should be a <ul> with several <li> elements. The Item* components themselves do not know they are in a list.
<WrapItems>
<ItemA/>
<ItemB/>
<ItemC/>
<ItemD/>
</WrapItems>
I can produce the DOM result I want by iterating the react children and wrapping them in a li. However, some of these items are shared between several controls, motivating me to create a common component.
<WrapItems>
<ItemA/>
<CommonItems/>
<ItemD/>
</WrapItems>
Where CommonItems ends up rendering:
<>
<ItemB/>
<ItemC/>
</>
The issue is that I cannot wrap ItemB and ItemC anymore, since React.Children will walk iterate the immediate children*.
Essentially I want CommonItems to be transparent and expose it's children directly to the WrapItems control, so that it can wrap them correctly. Is there a way to do this?
I've tried an approach where I replace the component with a useCommonItems function that returns an array of items instead. In some cases this can work, but in others it becomes a challenge, and a performance concern. Some of these parts are conditional, and the use approach forces them to all end up non-conditionally evaluated, along with all their use... functions in turn.
*Note, I'm aware that React.Children.map does not iterate over fragments, but I can solve that part by doing my own Children.map that descends into fragments. The issue in this question is about iterating over the children of components. The solution may be related, I'm not sure.
Say I am building an instant messaging with app with React (I'm not doing that exactly, but this is easier to explain). I have a sidebar with a list of conversations and, when you click one, it is shown on the right (similar to this). I don't want to mount each conversation component until the user clicks it, but I don't want to unmount it, just hide it, when they click on another conversation. How can I do this cleanly? There will never be more than about 30 chats for any user.
You can store the enabled conversations in an array that you use to show, and when you disable a conversation you can just add a hidden prop to it which you pass to the conversation and make it return null. This will make it not render anything but will not unmount it since you have not removed it from the array that handles the display of conversations.
example at: https://codesandbox.io/s/wispy-forest-59bqj
This is a bit hard to answer since you haven't posted the code.
But, theoretically, the best way to approach this problem is to transfer the data from your sidebar component and load it onto the right component on a per-user basis. You don't have to mount each "conversation component".
You can do this by with the boolean hidden property in your markup. React will render as usual and simply pass it along to the html, the browser will then simply not paint it.
const HideMe = ({ isHidden }) => (
<div hidden={isHidden}>
can you see me?
</div>
)
I made an example for you:
https://codesandbox.io/s/elastic-curie-t4ill?file=/src/App.js
reference: https://www.w3schools.com/tags/att_hidden.asp
I am trying to hide an element 'GorillaSurfIn' after I click on it.
But also it should fire the 'setShouldGorillaSurfOut' to 'true'. The second part works, but after I added this function:
function hideGorillaSurfIn() {
let element = document.getElementById('gorilla-surf-in');
ReactDOM.findDOMNode(element).style.display =
this.state.isClicked ? 'grid' : 'none';
}
After I click, the code falls apart.
Once I click, the element should be hidden/removed till the next time the App restarts.
Here is the Code Sandbox Link for further explanation.
I am open to any solutions, but also explanations please, as I am still fresh in learning React.
I have changed your code a bit to make it work. You can make further changes according to your need. A few things that I would like to add: -
You should avoid using findDOMNode (in most cases refs can solve your problem) as there are certain drawbacks associated with findDOMNode, such as the react's documentation states "findDOMNode cannot be used with functional components".
I've used refs (forward ref in this case) to make it work.
GorillaSurfIn was called twice, so there were two Gorilla gifs on the screen with same IDs. Not sure if that was the intended behaviour but each element should have unique ID.
Check out the code sandbox.
I'm trying to clarify the pros/cons of having a new function declaration within react's render method.
Consider a render method like the following:
render () {
return (<SomeComponent somePropWithoutEventBind={() => console.log('not so dangerous?')} />)
}
In the above example, somePropWithoutEventBind doesn't bind to a DOM event: react will check for prop changes and every time render is called this prop has changed - because it's a new function - so it never matches the previous, this is expensive but nothing tremendous.
Now in this case
render () {
return (<input onChange={() => console.log('dangerous?')} />)
}
onChange prop does bind to DOM (doing something like addEventListener) so every render will have to removeEventListener and addEventListener again? Is this the main reason behind avoiding to declare functions inside the render method?
If possible, please justify your answer pointing to react source code.
The main reason of avoiding defining new functions in render is to avoid over rendering.
Consider bind a new function onto a DOM element (react element not real DOM) like so: <button onClick={_ => this.setState({ hide: true })}>Hide Me</button>} there's almost none cost at all, since DOM elements gets re-rendered anyways. (site note: react doesn't use native DOM events like add/removeEventListener, it uses SyntheticEvent and your code targets virtual DOM aka react element not real DOM)
However for a custom components (In large codebase we typically have lots of complex Container Component composed of Functional/Class Child Components. Let's say you have something like
render() {
// you won't run into unnessary re-render issue
// when you use `onClick={this.handleClick}` since the function reference doesn't change
// while most perf tricks done by react bindings are relying on shallow compare of props/state
return (
<ComplexContainer onClick={_ => this.setState({ forceReRender: true})}>
<Child1 />
<Child2>
<NestedChild1 />
<NestedChild2 />
</Child2>
</ComplexContainer>
)
}
If you do this way, this will cause the whole render tree starting from ComplexContainer to re-render, this may have notable negative perf impacts, but you will need DevTools profiling to benchmark.
In fact, the real thing i wanna say is: it might not be that huge as you concern, avoid premature optimization can be more important. Give this awesome reading material a shot: React, Inline Functions, and Performance
A bit more info regarding react synthetic event system here, it's simply a wrapper of native DOM events to normalize the subtle differences of events among different browser vendors. The API would be the same event.preventDefault()/event.preventPropagation() etc works as it is, but you get cross-browser compatibility for free. Regarding how it works internally please see event delegation