有效地渲染大量Redux表单字段?

Jor*_*nev 5 javascript reactjs redux redux-form react-redux

我每天都有一张员工表和他们的每月工作时间。在这里,我们可以批量更新所有员工工时值。

本月的一个简单数学:30天x 50名员工将产生1500个安装的Redux表单字段。

每次挂载Field时,Redux Form都会调度一个操作以在Redux存储中注册Field。因此,调度了1500个事件。

使用Chrome-> Performance工具进行调试,我发现从安装到分派到呈现Fields的整个过程大约需要4秒钟:

绩效成本

上面的性能得分基于我使用React,Redux,Redux Form和Reselect创建的以下简单工作示例:

/* ----------------- SAMPLE DATA GENERATION - START ----------------- */
const generateEmployees = length =>
  Array.from({ length }, (v, k) => ({
    id: k + 1,
    name: `Emp ${k + 1}`,
    hours: [8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8]
  }))

const employees = generateEmployees(50)
/* ----------------- SAMPLE DATA GENERATION - END ------------------- */

/* --------------------- INITIALIZATION - START --------------------- */
const { reduxForm, Field, reducer: formReducer } = ReduxForm
const { createStore, combineReducers, applyMiddleware } = Redux
const { Provider, connect } = ReactRedux
const { createSelector } = Reselect

// Creating the Reducers
const employeesReducer = (state = employees) => state
const reducers = {
  form: formReducer,
  employees: employeesReducer
}

// Custom logger.
// The idea here is log all the dispatched action,
// in order to illustrate the problem with many registered fields better.
const logger = ({ getState }) => {
  return next => action => {
    console.log("Action: ", action)
    return next(action)
  }
}

const reducer = combineReducers(reducers)
const store = createStore(
  reducer,
  window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__(),
  applyMiddleware(logger)
)
/* --------------------- INITIALIZATION - END ----------------------- */

const renderEmployees = employees =>
  employees.map(employee => {
    return (
      <tr key={employee.id}>
        <td>{employee.id}</td>
        <td>{employee.name}</td>
        {employee.hours.map((hour, day) => (
          <td key={day}>
            <Field component="input" name={`${employee.id}_${day}`} />
          </td>
        ))}
      </tr>
    )
  })

const FormComponent = ({ employees, handleSubmit }) => {
  return (
    <form onSubmit={handleSubmit}>
      <h2>Employees working hours for November (11.2018)</h2>
      <p>
        <button type="submit">Update all</button>
      </p>
      <table>
        <thead>
          <tr>
            <th>ID</th>
            <th>Name</th>
            {Array.from({ length: 30 }, (v, k) => (
              <th key={k + 1}>{`${k + 1}.11`}</th>
            ))}
          </tr>
        </thead>
        {renderEmployees(employees)}
      </table>
    </form>
  )
}

const Form = reduxForm({
  form: "workingHours",
  onSubmit: submittedValues => {
    console.log({ submittedValues })
  }
})(FormComponent)

const getInitialValues = createSelector(
  state => state.employees,
  users =>
    users.reduce((accumulator, employee) => {
      employee.hours.forEach(
        (hour, day) => (accumulator[`${employee.id}_${day}`] = hour)
      )

      return accumulator
    }, {})
)

const mapStateToProps = state => ({
  employees: state.employees,
  initialValues: getInitialValues(state)
})

const App = connect(mapStateToProps)(Form)

ReactDOM.render(
  <Provider store={store}>
    <App />
  </Provider>,
  document.getElementById("root")
)
Run Code Online (Sandbox Code Playgroud)
table {
  border-collapse: collapse;
  text-align: center;
}

table, th, td {
  border: 1px solid black;
}

th {
  height: 50px;
  padding: 0 15px;
}

input {
  width: 20px;
  text-align: center;
}
Run Code Online (Sandbox Code Playgroud)
<script src="https://unpkg.com/react@15.5.4/dist/react.js"></script>
<script src="https://unpkg.com/react-dom@15.5.4/dist/react-dom.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/redux/3.6.0/redux.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-redux/5.0.4/react-redux.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/redux-form/6.7.0/redux-form.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/reselect/3.0.1/reselect.js"></script>

<div id="root">
    <!-- This element's contents will be replaced with your component. -->
</div>
Run Code Online (Sandbox Code Playgroud)

那么,我是否对Redux Form进行了效率低下和错误的操作,还是一次渲染大量Fields是瓶颈,我应该采取其他方法(分页,延迟加载等)吗?

Kra*_*mir 1

您是否尝试过https://www.npmjs.com/package/react-virtualized我在一个捕获数十个事件的项目中使用了它。该列表正在不断增长,这个组件帮助我渲染了所有这些。我不确定 Redux Form 是如何工作的,但如果它基于安装,那么我想这是一个不错的选择。