Update sibling component on mutation? - reactjs

Let's assume that I have the following structure:
<div>
<Form />
<List />
</div>
Current setup: query is in <List /> component and mutation is in <Form /> component. Because <Form /> doesn't have query, getFatQuery cannot do it's compare magic and it only returns clientMutationId which ultimately means that list data doesn't get updated without page refresh.
How could I make this work? I need separate form component because I want to make mutation in modal. Should I make mutation itself in <List /> and "transport" data from <Form /> to <List />?
I have lots of similar situations where I want to instert data (form component) in separate component, what's the strategy for these situations?

You're attempting to do state management with React which, as you note, can be confusing since there is no easy way to "pass data around" components in your hierarchy.
A common solution is to have a parent component hold the data and have your Form and List components react to this data, changing it only through callbacks passed down from this parent component.
Another common solution is to add Redux to your application to handle the application level state data. This one allows you to keep all data in a single object called a store, making it easy for any component to subscribe to changes, therefore eliminating the need for a parent component doing data passing.

Related

Pass formik validation errors to parent component

I am creating a component that internally has other 2 components with Formik each one, I did it in that way because each internal component submits separately on blur.
What I want to do is, once Formik validates, the errors should be showed within the parent component.
This is a quick example of the structure:
<ParentComponent>
<FirstInputField onChange={firstChangeHandler} />
<Divider />
<SecondInputField onChange={secondChangeHandler} />
<ErrorMessages>I WANT ERRORS TO BE HERE</ErrorMessages>
</ParentComponent>
The first approach was to send an "onError(error)" to the child component and call it to update the state on the parent component with the errors but I am getting a warning.
Cannot update a component (parent) while rendering a different component (child)
So I'd like to see if there is another way to do this.
Context Api to manage the error state would solve your issue.
Reference for similar implementation you can check this post.

React component not re-rendering with new props unless I change key

I'm making an app that displays a lot of graphs, so in order to prevent unnecessary re-rendering I've been going through my components and seeing where I can implement shouldComponentUpdate to improve efficiency. But after doing so in some of the higher up components I'm getting a weird bug with the graph component itself. I have the generic <Graph/> parent component with this render:
render() {
return(
<div>
{ this.getGraph() }
</div>
);
}
and the getGraph() essentially returns this:
return React.createElement(graphComponentMapping[graphType], {data:this.state.data,...this.state.configuration});
where graphComponentMapping[graphType] is a <Table/> component (or various other ones, but we'll focus on table for now). Now in that <Table/> component I render this:
return(
<ReactTable {...this.getParameters()} data={data} columns={columns} />
);
and the getParameters() function essentially just looks through the configuration prop and gets all the properties relevant to the React Table component.
Now, when I initially render the <Table/>, it has the correct configuration (i.e. if I change the initial config the table matches that). But when I update the configuration prop in the <Graph/> parent, the table doesn't update accordingly. The render function in <Table/> is called again, and if I print this.props in the table's render I can see that various configuration properties have changed, e.g. this.props.defaultPageSize has changed from say 5 to 3, but the table doesn't re-render to reflect this. Even in the browser's React dev tools I can see the props have changed.
If I force a complete a re-render of the element by using a random key, e.g.
return(
<ReactTable {...this.getParameters()} data={data} columns={columns} key={Math.random()} />
);
then it works, and the table updates when I pass new configuration props. Why doesn't it update when receiving new props, only when I force it to completely re-render?
I have faced such problem but that was primarily the way my redux store was setup.
Redux object is reference based so even just updating the properties, it wasn't telling my React component that something has changed. To solve this, I had to create a new object and update value there and then use it, which solved the issue.
this could be the reason they key having a random number is causing your whole component to re-render.

Reactjs - data flow

I have a general question about where to load data in Reactjs.
The main component is called App. Then the App returns 3 components: Header, Body, and Footer. Now within Body, there is a Tab component, which is further subdivided into a few components including a component called "grids".
Now I want my data (after being filtered) displayed in Grids.
Please correct me if I'm doing it wrong but my thinking is:
Load data in the main component App as state:
Pass it to Body with:
<Body data={this.state.data} />
In the Body component, pass it further as:
<Tabs data={this.props.data} />
In the Tabs component, pass it further as:
<Grids data={this.props.data} />
In Grids, write all the methods to filter data and display/return it accordingly.
Is this correct?
Thanks
The flow you've outlined is correct. An alternate approach is to use context: Anything set into context of one component is available to every descendent of that component, without setting props of intermediate components.
Context comes with a warning though:
Using context will make your code harder to understand because it
makes the data flow less clear. It is similar to using global
variables to pass state through your application.
BTW, for managing data, I'd use something like Flux or Redux. Managing data directly within React components quickly becomes a pain in a** as application grows. Flux/Redux, on the other hand, scale very well.

ReactJS: Why use this.props.children?

I've realised that none of the components I write use {this.props.children}.
I tend to compose my components the way the official docs state at the top of https://facebook.github.io/react/docs/multiple-components.html.
Is nesting the components like this...
<A>
<B />
<C />
</A>
...beneficial over composing them like this?:
A.js
render() {
<B />
<C />
}
Presuming that's the right terminology, what am I missing?
In my applications I rarely use this.props.children, because I often know specifically what children I want to render. In libraries, or components written to be re-used outside of a specific component hierarchy, I've seen it often. I think this.props.children has more relevance to that use-case.
Edit: I thought I'd elaborate on some cases that this.props.children can come in handy. One such example is when creating components which follow the 'render prop' pattern. i.e. I've got some components that require pulling data in from multiple 'render prop' HoC's, such as an Apollo Query component as well as a state management HoC. I combined all my different data sources into one HoC and then called children as a function, passing in the result of pulling out all the data I needed. That being said these days I prefer and look forward to wider adoption of Hooks as an alternative to render props.
Really any component which you want to render arbitrary children; another example I've used props.children is when creating a HoC that required a user be authenticated before rendering the child, redirecting to a login screen when the user isn't logged in. I could wrap any of my 'protected' screen components with this auth HoC.
It's still something the majority of my components don't use, but just another tool to be applied when the situation warrants.
I'd say it would be useful when you don't know what you want to render.
For instance, you have a tooltip wrapper, let's say it's A component in your scenario, and you can use it to pass different content:
<A>
<div>Some text...</div>
<ImageComponent /> // render an image as well
</A>
Or:
<A>
<div>Only text</div>
</A>
Some components don't know their children ahead of time. This is especially common for components like Sidebar or Dialog that represent generic "boxes".
We recommend that such components use the special children prop to pass children elements directly into their output:
Read More...
Children is a special prop that can be passed from the owners to the components defined inside their render method. It allows us to customize a structure of a component.
With props, a child component keeps its structure under the full control and only certain attributes or values are allowed to be passed. The structure of the component is hard coded.
In the React documentation, children property is described as opaque, because it is a property that does not tell anything about the value it contains. As a result it allows a client/parent to customize a structure.
We can also say, that the components defines only a kind of basic template/structure, for instance by providing a kind of "header". And the consumer reuses this header structure, by adding children.

How to listen for changes in prop state in React.js?

I am porting over a Backbone.View into React. I might be missing something, but I cannot figure out the idiomatic way to make the state of a component dependent on the states of their sibling. For example, say that I have a component like this:
<Timeline>
<Page selected="true" onClick={this.handleClick} />
<Page selected="false" onClick={this.handleClick}/>
</Timeline>
And let's say all handleClick does it to setState({selected: true}). My question is how do I make sure that the state of the siblings of this component are set to false before it is set to true.
My ideal solution would be to listen for changes in prop state and forceRender the sub-components from the Timeline component, but I don't know if this is an accepted approach.
I am also looking for alternative ways to implement this component, since I understand the recommended way to decompose the components is to keep them as stateless as possible to ensure they can be reused elsewhere.
In cases where siblings seem to have interdependent state, you'll want to hoist up the relevant pieces of state up to the parent component.
In this case, you probably want to store selectedPage on the parent's state object, causing the render method to look like
<Timeline>
<Page selected={this.state.selectedPage === 1} onClick={this.handleClick} />
<Page selected={this.state.selectedPage === 2} onClick={this.handleClick} />
</Timeline>
or similar. When you want to change the selected page, simply change the selectedPage value stored on the parent, possibly from within a callback passed to the children.
By following this pattern, you can ensure that the two pages are always in sync with each other -- each time the parent rerenders the props will be updated simultaneously on the two children.

Resources