Где поместить функцию инициализации `componentWillMount`, которая изменяет состояние?

на моем ubuntu 14.04, apache 2.4, php 5.5.9 install, я попробовал с sample.php on / var / www / html (root по умолчанию), и он работал нормально. Таким образом, проблема была в моей конфигурации виртуальных серверов. Решение заключалось в том, чтобы включить в директорию def, содержащую .php, следующую строку:

    php_admin_flag engine on
0
задан David Deprost 24 March 2019 в 20:41
поделиться

3 ответа

initGrid вовсе не обязательно должен быть частью компонента, он не привязан к состоянию, за исключением того, что он пытается его обновить.

Он может быть вспомогательной функцией и использоваться при необходимости:

function initGrid(rows) {
    ...
    return {
      rows,
      grid,
      fullColumns,
    };
}

class App extends React.Component {
  state = initGrid(6);
  ...
}
0
ответ дан estus 24 March 2019 в 20:41
поделиться
1120 Я некоторое время думал об этой проблеме и придумал несколько решений, у каждого из которых есть свои компромиссы. Я документирую их здесь, чтобы они все еще могли быть полезны для других, сталкивающихся с этой проблемой. Выберите решение, которое наилучшим образом соответствует потребностям вашего проекта:

  • Создайте дублирующую функцию initGrid, предназначенную для использования только в конструкторе (присваивая непосредственно this.state вместо использования setState) , Помимо дублирования кода и явного нарушения DRY, это также создает дополнительный метод «одноразового использования» , который приводит к предупреждению «Не изменять состояние напрямую, используйте setState ()», что довольно раздражает. .

  • Использовать анонимную самопризывающую функцию, которая присваивает непосредственно this.state.grid и this.state.fullColumns в конструкторе:

    constructor(props) {
      // ...
    
      [this.state.grid, this.state.fullColumns] = (function(rows) {
        let grid = [];
        let fullColumns = [];
        let cols = rows + 1;
        for (let c = 0; c < cols; c++) {
          fullColumns.push(false);
          let column = [];
          for (let r = 0; r < rows; r++) {
            column.push(null);
          }
          grid.push(column);
        }
        return [grid, fullColumns];
      })(this.state.rows);
    }
    

    componentWillMount теперь можно удалить. Это также избавляет от предупреждения «Не изменять состояние напрямую, используйте setState ()» и не приводит к бессмысленному созданию другого метода для одноразового использования. Но он все еще излишне дублирует код из this.initGrid.

  • Просто жестко закодируйте начальную сетку и массивы fullColumns в состоянии:

    constructor(props) {
      super(props);
      this.state = {
        rows: 6,
        grid: [
                [null, null, null, null, null, null],
                [null, null, null, null, null, null],
                [null, null, null, null, null, null],
                [null, null, null, null, null, null],
                [null, null, null, null, null, null],
                [null, null, null, null, null, null],
                [null, null, null, null, null, null],
              ],
        fullColumns: [false, false, false, false, false, false, false]
      }
    }
    

    componentWillMount теперь можно удалить. Это приносит в жертву настраиваемость и чувствует себя довольно непрофессионально. Однако, это не без его собственных преимуществ; это приводит к меньшему количеству логики, более эффективно, а также помогает в визуализации / документировании кода.

  • Измените функцию initGrid, чтобы отличать вызов ее от конструктора от вызова из другого места:

    initGrid(rows) {
      // Create grid data structure to keep track of which grid cells
      // contain checkers of which color:
      // 'grid' = array of COLUMN arrays!
      let cols = rows + 1;
      let grid = [];
      let fullColumns = [];
      for (let c = 0; c < cols; c++) {
        fullColumns.push(false);
        let column = [];
        for (let r = 0; r < rows; r++) {
          column.push(null);
        }
        grid.push(column);
      }
    
      // If 'this.state.grid' is already initialised (i.e. non-empty),
      // the call is NOT from inside the constructor:
      if (this.state.grid.length !== 0) {
        this.setState({
          rows,
          grid,
          fullColumns,
        });
      } else {
        // If the grid is empty, this call came from inside the constructor,
        // so we disable the "Do not mutate state directly, Use setState()" warning:
        // eslint-disable-next-line react/no-direct-mutation-state
        this.state = {
          ...this.state,
          grid,
          fullColumns,
        }
      }
    }
    

    Это не излишне дублирует код и сохраняет настраиваемость. Он по-прежнему имеет предупреждение «Не изменять состояние напрямую, используйте setState ()», но он глушит комментарий // eslint-.... Теперь мы можем вызвать this.initGrid(this.state.rows) в конструкторе, а не в componentWillMount.

    Это похоже на самое профессиональное решение для меня.

  • [Тысяча сто тридцать одна]
0
ответ дан David Deprost 24 March 2019 в 20:41
поделиться

Вы можете использовать его в конструкторе, просто замените

this.setState({
      rows,
      grid,
      fullColumns
    });

на

this.state = {
   ...this.state
   rows,
   grid,
   fullColumns
}
<час>

. Вы также можете переместить initGrid в метод componentDidMount путем рендеринга. null когда состояние компонента не полностью инициализировано или не обеспечивает значимых значений по умолчанию.

render() {
   if(this.state.grid) {
      return ...
   }
   else {
      return null;
   }
}
0
ответ дан abadalyan 24 March 2019 в 20:41
поделиться
Другие вопросы по тегам:

Похожие вопросы: