停止重新渲染父组件。仅重新渲染子组件

时间:2019-06-19 10:31:42

标签: javascript reactjs render react-select formik

我在Formik字段中有一个React-Select字段,当您从下拉选项中选择一个项目时,所有父组件都将重新呈现。这是容器中可用的最深的子组件。

它重新渲染了4个父母。这有点问题。我想将组件的重新呈现限制为仅自身。

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.

我尝试用shouldComponentUpdate来做到这一点,但是没有运气。我试图用SetState来做到这一点,但这虽然掉进了水里,但我却无法正常工作(出现了很多错误)。

-TLDR- 问题: 使组件仅将渲染保留到其自身。 FormikReact-Select中使用的外部组件。

这是代码:

            <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>

dependacies道具可以使这棵树跳到主表单Props,并重新渲染整个组件树。这也与我昨天遇到的另一个问题有关,即react-select的closeMenuOnSelect={false}无法正常工作。

^这是发生这种情况的原因。谢谢你。

2 个答案:

答案 0 :(得分:1)

我不知道您将如何使用正在使用的库来执行此操作。但是,当我不想让我的组件不必要地渲染时,我会使用React.memo来比较props对象,并确定是否需要更新。

From React DOCS

没有反应备忘录

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"/>

具有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"/>

答案 1 :(得分:0)

我将检查是否调用了Formik的onSubmit,并且是否正在触发树的重新渲染。如果您有一个带有type=button的按钮,可能会触发表单提交。

v2之前的Formik也存在一个错误,即如果通过rendercomponent属性提供了render函数,则每次更新时Field都会安装和卸载所有子级。相反,只需将render函数作为Fields子级传递。