简体   繁体   中英

Stop Re-Rendering of Parent Components. Only Re-Render Child Component

I have a React-Select Field, inside a Formik Field, that when you select an item from the dropdown options, all the Parent Components are rerendered. This is the deepest child component available in the Container.

And it re-renders 4 Parents. Which is kind of Problematic. I want to limit the rerender of the Component to only itself.

The above happens because each Child Process passes
props to the Container, which is the master form.
And onSubmit it takes all the info(props) and makes the API Call.

I tried doing it with shouldComponentUpdate but no luck. I tried to do it with SetState , but that though fell in the water, as I couldn't make it work(Got a ton of errors).

--TLDR-- THE PROBLEM: Make a Component retain the rendering to only itself. External Components used in it Formik and React-Select .

Here is the code for that:

            <div className="w-50">
              <Field
                name={`${keyField}.${index}.permissions`}
                render={({ field: { value, name }, form: { setFieldValue, setFieldTouched } }) => (
                  <div>
                    <label htmlFor="namespace-permissions" className="font-weight-medium">
                      Permissions in Namespace <Asterisk />
                    </label>
                    <Select
                      isMulti
                      closeMenuOnSelect={false}
                      id="namespace-permissions"
                      defaultValue={convertNamespaceToDefaultValue(
                        dependencies.namespacePermissions,
                        value
                      )}
                      options={convertNamespaceToSelect(dependencies.namespacePermissions)}
                      onChangeCallback={values => {
                        setFieldValue(name, convertSelectToNamespacesData(values));
                        setFieldTouched(name, true);
                      }}
                    />
                    <ErrorMessage name={name} component={FormErrorMessage} />
                  </div>
                )}
              />
            </div>

The dependacies prop is what makes the trip up the tree, to the master form Props, and rerenders the entire Component Tree. This also, ties with another question I had yesterday, about react-select's closeMenuOnSelect={false} not working correctly.

^This is the reason why that happens. Thank you..

I don't know how you would be able to do this with the libraries that you're using. But when I don't want my components rendering unnecessarily I use React.memo it will shallow compare the props object and decide if needs to update.

From React DOCS

WITHOUT REACT MEMO

 function App() { return( <Parent1/> ); } function Parent1(props) { console.log('Rendering Parent1...'); const [parentState,setParentState] = React.useState(true); return( <Parent2 setParentState={setParentState} /> ); } function Parent2(props) { console.log('Rendering Parent2...'); return( <Child setParentState={props.setParentState} /> ); } function Child(props) { console.log('Rendering Child...'); return( <button onClick={()=>props.setParentState((prevState)=>!prevState)}>Update ParentState</button> ); } ReactDOM.render(<App/>, document.getElementById('root'));
 <script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.3/umd/react.production.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.3/umd/react-dom.production.min.js"></script> <div id="root"/>

WITH REACT.MEMO

 function App() { return( <Parent1/> ); } function Parent1(props) { console.log('Rendering Parent1...'); const [parentState,setParentState] = React.useState(true); return( <Parent2 setParentState={setParentState} /> ); } const Parent2 = React.memo(function Parent2(props) { console.log('Rendering Parent2...'); return( <Child setParentState={props.setParentState} /> ); } ); const Child = React.memo(function Child(props) { console.log('Rendering Child...'); return( <button onClick={()=>props.setParentState((prevState)=>!prevState)}>Update ParentState</button> ); } ); ReactDOM.render(<App/>, document.getElementById('root'));
 <script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.3/umd/react.production.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.3/umd/react-dom.production.min.js"></script> <div id="root"/>

I would check if Formik's onSubmit is being called and if that's triggering the tree to re-render. If you have a button with type=button that could be triggering a form submit.

There is also a bug with Formik before v2 where Field will mount and unmount all of it's children on every update if given the render function through render or component prop. Instead just pass the render function as the Fields child.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM