如何避免重新渲染数组中的元素?

时间:2018-03-02 00:33:49

标签: javascript reactjs redux-form

我有一个数组,我想将这个数组渲染成几个redux形式。我发现所有表格都被重新渲染。代码如下所示:

Form.jsx

import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { Link, Events, scrollSpy } from 'react-scroll';
import styles from './Form.css';
import MultipleForm from './MultipleForm';

class Form extends Component {
  constructor(props) {
    super(props);
    const {
      workflows,
    } = this.props;
    this.state = {
      curTab: workflows.length > 0 ? workflows[0] : '',
      curForm: '',
    };
  }

  componentDidMount() {
    Events.scrollEvent.register('begin');
    Events.scrollEvent.register('end');
    scrollSpy.update();
  }
  componentWillReceiveProps(nextProps) {
    const {
      workflows,
    } = nextProps;
    if (workflows && workflows.length > this.props.workflows) {
      this.setState({
        curTab: workflows[0],
      });
    }
  }
  componentWillUnmount() {
    Events.scrollEvent.remove('begin');
    Events.scrollEvent.remove('end');
  }
  handleChangeTab = (value) => {
    this.setState({
      curTab: value,
    });
  }

  handleActiveTab = (workflow) => {
    console.log(workflow);
  }


  render() {
    const {
      workflows,
      schemaNames,
      ...rest
    } = this.props;
    return (
      <div className={styles.container}>
        <header>
          <PerspectiveBar
            value={this.state.curTab}
            onChange={this.handleChangeTab}
            style={{
              position: 'fixed',
              left: '0',
              top: '48px',
              width: '100vw',
              zIndex: '1380',
            }}
          >
            {workflows.map(wf => (
              <PerspectiveTab
                key={wf}
                label={wf}
                value={wf}
                onActive={() => this.handleActiveTab(wf)}
              />
          ))}
          </PerspectiveBar>
        </header>
        <div className={styles.formContainer}>
          <Paper className={styles.paperContainer}>
            <MultipleForm
              workflow={this.state.curTab}
              schemaNames={schemaNames}
              {...rest}
            />
          </Paper>
        </div>
        <Drawer className={styles.drawer} containerStyle={{ height: 'calc(100% - 104px)', top: '104px' }}>
          <div className={styles.drawerContainer}>
            {schemaNames.map(schemaName => (
              <Link
                onSetActive={(to) => {
                  this.setState({
                    curForm: to,
                  });
                }}
                to={schemaName}
                duration={500}
                offset={-104}
                spy
                smooth
              >
                <MenuItem
                  checked={this.state.curForm === schemaName}
                >
                  {schemaName}
                </MenuItem>
              </Link>
            ))}
          </div>
        </Drawer>
      </div>

    );
  }
}

Form.propTypes = {
  schemaNames: PropTypes.arrayOf(PropTypes.string),
  workflows: PropTypes.arrayOf(PropTypes.string),
  fetchSchemaNames: PropTypes.func.isRequired,
};

Form.defaultProps = {
  schemaNames: [],
  workflows: [],
};

export default Form;

MultipleForm.jsx

import React, { Component } from 'react';
import PropTypes from 'prop-types';
import FlatButton from 'material-ui/FlatButton';
import { Element } from 'react-scroll';
import SchemaForm from './SchemaForm';

class MultipleForm extends Component {
  componentDidMount() {
    console.log('MultipleForm Mounted');
    const {
      workflow,
      fetchSchemaNames,
    } = this.props;
    if (workflow) fetchSchemaNames(workflow);
  }

  componentWillReceiveProps(nextProps) {
    const {
      workflow,
      fetchSchemaNames,
    } = nextProps;
    if (workflow && this.props.workflow !== workflow) fetchSchemaNames(workflow);
  }

  componentDidUpdate() {
    const {
      schemaNames,
      schemas,
      initialValues,
      fetchSchemas,
      fetchInitialValues,
    } = this.props;
    const schemasNeedToFetch = this.remainingSchemas(schemaNames, schemas);
    if (schemasNeedToFetch.length !== 0) fetchSchemas(schemasNeedToFetch);
    const initialValuesNeedToFetch = this.remainingInitialValues(schemaNames, initialValues);
    if (initialValuesNeedToFetch.lenght !== 0) fetchInitialValues(initialValuesNeedToFetch, 1);
  }

  remainingSchemas = (schemaNames, schemas) =>
    schemaNames.filter(schemaName => schemaName in schemas === false).sort();

  remainingInitialValues = (schemaNames, initialValues) =>
    schemaNames.filter(schemaName => schemaName in initialValues === false).sort();

  handleSubmitAll = (event) => {
    event.preventDefault();
    const {
      submit,
      schemas,
      schemaNames,
    } = this.props;
    schemaNames
      .map(schemaName => schemas[schemaName].title)
      .forEach((title) => {
        submit(title);
      });
  }

  render() {
    const {
      schemaNames,
      schemas,
      initialValues,
      postForm,
    } = this.props;
    schemaNames.sort((a, b) => a.localeCompare(b));
    return (
      <div>
        {schemaNames.map(schemaName => (
          <Element name={schemaName}>
            <SchemaForm
              key={schemaName}
              schema={schemas[schemaName]}
              initialValue={initialValues[schemaName]}
              schemaName={schemaName}
              postForm={postForm}
            />
          </Element>
        ))}
        <div>
          <FlatButton
            label="Submit"
          />
          <FlatButton label="Deploy" />
        </div>
      </div>);
  }
}

MultipleForm.propTypes = {
  workflow: PropTypes.string.isRequired,
  submit: PropTypes.func.isRequired,
  fetchSchemaNames: PropTypes.func.isRequired,
  schemas: PropTypes.object,
  schemaNames: PropTypes.arrayOf(PropTypes.string),
  initialValues: PropTypes.object,
  fetchSchemas: PropTypes.func.isRequired,
  fetchInitialValues: PropTypes.func.isRequired,
  postForm: PropTypes.func.isRequired,
};

MultipleForm.defaultProps = {
  schemaNames: [],
};

export default MultipleForm;

SchemaForm

import React, { Component } from 'react';
import PropTypes from 'prop-types';
import Liform from 'liform-react';
import theme from './NokiaTheme';
import styles from './Form.css';

class SchemaForm extends Component {
  componentDidMount() {
    console.log('schema mounted');
  }

  shouldComponentUpdate() {
    return false;
  }
  handleSubmit = (value) => {
    const {
      postForm,
      schemaName,
    } = this.props;
    postForm(value, schemaName, 1);
  }


  render() {
    const {
      schema,
      initialValue,
    } = this.props;
    console.log('props', this.props);
    return (
      <div>
        <h3 id={schema.$id} className={styles.formTitle}>
          {schema.title}
        </h3>
        <Liform
          schema={schema}
          onSubmit={value => this.handleSubmit(value)}
          destroyOnUnmount={false}
          theme={theme}
          initialValues={initialValue}
        />
      </div>
    );
  }
}

SchemaForm.propTypes = {
  schema: PropTypes.shape({
    $id: PropTypes.string,
  }),
  initialValue: PropTypes.object,
  schemaName: PropTypes.string,
  postForm: PropTypes.func.isRequired,
};

SchemaForm.defaultProps = {
  schema: {},
  initialValue: null,
  schemaName: '',
};

export default SchemaForm;

仅通过添加或删除某个元素来更改schemaNames。例如:schemaNames将从['A', 'B', 'C']更改为['A', 'B', 'D']。我从redux中获取了schemaNames。我在网上获取。

但是当我检查ConnectedReduxForm时,当我更改schemaNames时,将卸载SchemaForm并且react将再次安装表单。我试过将ConnectedReduxForm设置为PureComponent。这没用。

有人可以帮助我吗?我花了很多时间,没有任何帮助。

更新:我发现了问题,原因是我每次更新工作流时,都需要从服务器获取schemaNames。但我仍然不知道为什么会发生这种情况。有人可以解释一下吗?

0 个答案:

没有答案