Pass formik validation errors to parent component - reactjs

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.

Related

passing props form child to parent component in react

return
<div>
<RadioOptions />
<GenButton />
<OutputPass />
</div>
I recently worked on my side-project and I found an issue in my code. inRadiooptions  I used some useState hooks, and I want to pass that state from Radiooptions component to its parent(passGen) and then from there, pass that state toGet Button component to check some condition and if nothings wrong, generate the password. (I'll also attach my GitHub repo for better access to my source code)
https://github.com/arviinmo/palora/tree/main/components/passwordgenerator
You can't pass props from child to parent in React, it's only one way (from parent to child).
You should either:
Put the state in the parent component and manipulate it from the child component by passing the setter function in the props
Use something like Redux Toolkit to create a global state that all components can have access to

React component state becomes invalid after change in parent component

function UserCard({ user }) {
let defaultUserName = user.nicknames[0];
let [selectedNickname, setSelectedNickname] = React.useState(defaultUserName);
// The selected nickname becomes invalid when the user is changed!!!
const selectedNicknameIsValid = user.nicknames.includes(selectedNickname);
return (<div>
<UserCardWithNickName user={user} selectedNickname={selectedNickname} />
<SelectNickName user={user} setSelectedNickname={setSelectedNickname} />
</div>);
In the above snippet the component's state holds the selected nickname from the list of user nicknames. But when the user changes in the parent component this component is re-rendered with the same state. So the nickname in the state is for the wrong user.
What is the preferred way to handle this? A lot of google searching couldn't find much discussion.
Am I doing this in some fundamental non-react way?
Is the preferred solution to use useEffect to fix the state when it becomes invalid as discussed here React.useState does not reload state from props?
Working example on codesandbox
Yeah, state changes in the parent component will usually re-render the child component, and hence reset the state of the child component. I'd suggest moving states that you want preserved up into the parent tree.
State management is an important concept in React. As your app grows, you'll realize doing this will add a lot of bloat and repetitive code. Learning about state management will prove very useful for you!
Yes. The link you have posted is one way to do it. The question you have to look for is if your child component is managing the value of selectedNickname in anyway. That is the only reason you would want to keep it as a seperate state in the child component. If all it does is read the props from the parent, simply use the props and do not maintain an internal state at all.
Months later I finally found a robust discussion of this problem in the react docs.
https://reactjs.org/blog/2018/06/07/you-probably-dont-need-derived-state.html
The problem I was trying to describe is called derived state.
I eventually solved it by adding a key when using the component. When a key changes, React will create a new component instance rather than update the current one. This is one of the recommended approaches in the docs.
<UserCard user={user} key={user.id} />

React input losing focus when passing value prop through Router "component" attribute

having a major brain fart today. I've tried a bunch of solutions to variations of this problem to no avail. It's an off-week for me and my brain, so I'm sure I'm just missing something stupid.
I'm trying to figure out why my Input component is re-rendering in a way that the input loses focus every time it receives value changes.
I need the username value to be stored in the App component.
I'm guessing it has to do with this Route "component" attribute returning a function, but I'm not entirely sure. I've also tried adding a key prop to various places throughout the app, but no luck.
Here's a link to a watered down codesandbox project.
And this is where I'm guessing something's happening.
component={() => (
<Input value={username} handleValueChange={handleUserNameChange} />
)}
Try instead of component using the render function. In the documentation for component it mentions the component will be re-mounted/re-created every render, which is why you are losing focus:
When you use component (instead of render or children, below) the
router uses React.createElement to create a new React element from the
given component. That means if you provide an inline function to the
component prop, you would create a new component every render. This
results in the existing component unmounting and the new component
mounting instead of just updating the existing component. When using
an inline function for inline rendering, use the render or the
children prop (below).
<Route
exact
path="/input"
render={() => (
<Input
key={"foo"}
value={username}
handleValueChange={handleUserNameChange}
/>
)}
/>
Here is an example in action.

Weird component lifecycle with react router

I have this route (simplified)
<Route
path="/foo/:id">
render={({match}) => (
<Page key={match.params.id} id={match.params.id}/>
)}
</Route>
Now the reason for that is that when I go from /foo/1 to /foo/2 I don't want to clear and update state of an existing component, it's too complex in my case. So I have a dynamic key which causes to unmount the /foo/1 component and mount a brand new /foo/2 component.
So far so good. But here is the catch. The lifecycle I observed is this
/foo/1 re-render
/foo/2 constructor
/foo/2 componentDidMount
/foo/1 componentWillUnmount
/foo/2 render
Why doesn't the first component unmount before the second one mounts? Because of that I get weird re-renders and glitches (it's connected to redux store and initialization of the /foo/2 component changes the store which manages to re-render still existing component /foo/1). Any ideas how to avoid this?
Thanks
It is hard to determine exactly what is happening with your short snippet of code, but, I believe your issues are relating to some anti-patterns;
A react component constructor should only be used for two things:
Initialising local state
Binding event handlers
https://reactjs.org/docs/react-component.html#constructor
Secondly you are using the render prop with a inline function, this means when ever a matching route is detected and the parent component re-renders it will re-construct the component, un-mounting it first then mounting it again. To prevent this you should be defining the render function outside of the parents render function.
Thirdly because you have a dynamic route /foo/:id and assigning the value of :id to the key of the child component react sees it as a different component and doesn't unmount it until the current render process has reached the un-mounting stage. This means that for a short period of time you have <Page key={1} /> & <Page key={2}/> present.
Because these three issues, you are getting what seems to be a weird component lifecycle but in fact it is react doing exactly what you told it to do.
The Solution:
Move the redux action being invoked in the constructor of the <Page /> to be in the componentDidMount() function.
Move the inline render function to be outside the parent render function.
Remove the key prop.

Update sibling component on mutation?

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.

Resources