Задать вопрос
Ответы пользователя по тегу React
  • Как составить компонент грамотно?

    0xD34F
    @0xD34F Куратор тега React
    Как Вы думаете, как бы написал опытный реакт-разработчик...
    Я конечно таковым ни разу не являюсь, но всё-таки скажу пару слов.

    проверки через тернарный оператор внутри render?
    Это окей - conditional rendering.

    render() {
        const paths = [
    Из метода render массив paths следует убрать. Может быть, его даже стоит сделать параметром компонента.

    onClick={ () => {this.setState({isOpen: !this.state.isOpen})} }
    Следует сделать метод. Создавать при каждом вызове render новый обработчик - само по себе не очень здорово, ну и ещё этот код повторяется дважды.

    this.props.history.listen(...
    Если предполагается, что во время работы приложения экземпляр компонента будет создаваться несколько раз, то при удалении экземпляра надо снимать обработчик, иначе вывод в консоль задвоится (затроится, зачетверится,...). Сделать это несложно - listen возвращает функцию, снимающую обработчик, так что:
    componentWillMount() {
      this.unlisten = this.props.history.listen(...
    
    componentWillUnmount() {
      this.unlisten();


    <Link className="next_btn"...
    <Link className="prev_btn"...
    Выглядят подозрительно похожими. Я бы рассмотрел вариант сделать под них отдельный компонент, который бы получал isOpen и свойства объектов paths[currPathIndex +/- 1] в качестве параметров.
    Ответ написан
    1 комментарий
  • Как найти индекс элемента массива, удовлетворяющего определённому условию?

    0xD34F
    @0xD34F Куратор тега React
    Это что-то вроде пагинации.

    Очень странно, но допустим:

    const currPathIndex = paths.findIndex(n => n.link === location.pathname);
    const isPrev = currPathIndex !== 0;
    const isNext = currPathIndex !== paths.length - 1;

    Дальше можно отключать кнопки:

    const onClick = e =>
      history.push(paths[currPathIndex + +e.target.dataset.step].link);

    <button disabled={!isPrev} data-step={-1} onClick={onClick}>PREV</button>
    <button disabled={!isNext} data-step={+1} onClick={onClick}>NEXT</button>

    Или не рендерить ссылки:

    {isPrev && <NavLink to={paths[currPathIndex - 1].link}>PREV</NavLink>}
    {isNext && <NavLink to={paths[currPathIndex + 1].link}>NEXT</NavLink>}

    https://jsfiddle.net/ev93d8fj/1/
    Ответ написан
    1 комментарий
  • Почему не перерисовывается компонент?

    0xD34F
    @0xD34F Куратор тега React
    почему он может не перерисовывается когда данные поступают?

    Ни почему.

    Компонент перерисовывается.

    С тем же результатом, что и без данных.

    Потому что забыли .length где-то здесь:

    Object.keys(this.props.landingState) > 0
    Ответ написан
    1 комментарий
  • Как получить текущий роут из React Router?

    0xD34F
    @0xD34F Куратор тега React
    Используйте withRouter.
    Ответ написан
    Комментировать
  • Как input полю при потере фокуса запретить прыгать?

    0xD34F
    @0xD34F Куратор тега React
    Делаем метод:

    onMouseDown(e) {
      e.preventDefault();
    }

    И добавляем его кнопке удаления значения в качестве обработчика соответствующего события:

    onMouseDown={this.onMouseDown}
    Ответ написан
    1 комментарий
  • Из-за чего появляется ошибка при setState?

    0xD34F
    @0xD34F Куратор тега React
    onClick={ this.setState({isOpen: !this.state.isOpen}) }

    А может, всё-таки стоит засунуть вызов setState в функцию?
    Ответ написан
  • Как запросить данные при загрузке страницы?

    0xD34F
    @0xD34F Куратор тега React
    Обращался к API в componentDidMount() и отправлял в стейт, но это вызывает перерендеринг компонента и в доках считается нежелательно.

    Это в каких доках? В тех, что известны мне, это прямо рекомендуется:

    You should populate data with AJAX calls in the componentDidMount lifecycle method. This is so you can use setState to update your component when the data is retrieved.
    Ответ написан
    5 комментариев
  • Как в React извлекать информацию из children?

    0xD34F
    @0xD34F Куратор тега React
    Собственно вопрос - как при фильтровании children понять, какой элемент является Column, какой GridToolbar и т.д.? Есть ли какие-либо хорошие практики для этого? Склоняюсь к тому, чтобы проверять свойство type.name, которое вроде как должно быть названием компонента, т. е. 'Column', 'GridToolbar' и т. д.

    Можно просто type, без name. Только, конечно, в этом случае сравнивать надо не со строкой, а с самим компонентом.

    Но должны ли это быть именно children?
    Есть вариант...
    ...оформить передачу каждого из элементов через отдельный prop:

    While this is less common, sometimes you might need multiple “holes” in a component. In such cases you may come up with your own convention instead of using children:

    function SplitPane(props) {
      return (
        <div className="SplitPane">
          <div className="SplitPane-left">
            {props.left}
          </div>
          <div className="SplitPane-right">
            {props.right}
          </div>
        </div>
      );
    }
    
    function App() {
      return (
        <SplitPane
          left={
            <Contacts />
          }
          right={
            <Chat />
          } />
      );
    }

    UPD. Вынесено из комментариев:

    Мне хочется в React достичь того, что называется слотами в Web Components и Vue.js.

    Окей, сделаем компонент слота:

    function Slot({ name, content, scope, children = null }) {
      const slotContent = []
        .concat(content || [])
        .filter(n => n.props.slot === name)
        .map(n => n.type === 'template'
          ? [].concat(n.props.children).map(m => m instanceof Function ? m(scope) : m)
          : n
        );
    
      return slotContent.length
        ? slotContent
        : children;
    }

    Пример использования - компонент таблицы с возможностью кастомизации внешнего вида столбцов (как заголовков, так и ячеек с данными):

    function Table({ columns, data, children }) {
      return (
        <table>
          <thead>
            <tr>{columns.map(n => (
              <th>
                <Slot name={`header.${n.name}`} content={children} scope={n}>
                  {n.label}
                </Slot>
              </th>))}
            </tr>
          </thead>
          <tbody>{data.map((row, index) => (
            <tr>{columns.map(({ name }) => (
              <td>
                <Slot name={`cell.${name}`} content={children} scope={{ name, row, index }}>
                  {row[name]}
                </Slot>
              </td>))}
            </tr>))}
          </tbody>
        </table>
      );
    }

    const COLUMNS = [
      { name:  'num', label:  'number' },
      { name:  'str', label:  'string' },
      { name: 'bool', label: 'boolean' },
    ];
    
    const DATA = [
      { num:  69, str:  'hello, world!!', bool: false },
      { num: 187, str:  'fuck the world', bool:  true },
      { num: 666, str: 'fuck everything', bool:  true },
    ];

    <Table columns={COLUMNS} data={DATA}>
    
      {/* в один слот можно передавать контент несколько раз */}
      <u slot="header.num" style={{ color:   'red' }}>NUM</u>
      <i slot="header.num" style={{ color: 'green' }}>!!!</i>
    
      {/* или, за один раз передавать несколько элементов */}
      <template slot="header.bool">
        boolean:
        <input type="checkbox" disabled />
        or
        <input type="checkbox" disabled defaultChecked />
      </template>
    
      {/* контент слота можно определять динамически */}
      <template slot="cell.bool">
        {({ row }) => <input type="checkbox" disabled defaultChecked={row.bool} />}
      </template>
    
    </Table>

    Можно даже сделать, чтобы было похоже на то, что вы показывали в тексте вопроса - добавляем компонент строки таблицы, экземпляры которого будут получать описания столбцов и контент слотов, вот как-то так:

    function TableColumn() {
      // да, всё правильно - тут пусто, этот компонент нужен только как место, где будет
      // собрано всё, что относится к столбцу, сам он ничего делать не должен
      return null;
    }
    
    function Table({ data, children }) {
      const columns = []
        .concat(children || [])
        .reduce((acc, n) => (
          (n.type === TableColumn) && acc.push(n.props),
          acc
        ), []);
    
      return (
        <table>
          <thead>
            <tr>{columns.map(({ children, ...n }) => (
              <th>
                <Slot name="header" content={children} scope={n}>
                  {n.label}
                </Slot>
              </th>))}
            </tr>
          </thead>
          <tbody>{data.map((row, index) => (
            <tr>{columns.map(({ name, children }) => (
              <td>
                <Slot name="cell" content={children} scope={{ name, row, index }}>
                  {row[name]}
                </Slot>
              </td>))}
            </tr>))}
          </tbody>
        </table>
      );
    }

    <Table data={DATA}>
    
      <TableColumn name="row-index" label="#">
        <template slot="cell">
          {({ index }) => -~index}
        </template>
      </TableColumn>
    
      <TableColumn name="num" label="number" />
    
      <TableColumn name="str" label="string" />
    
      <TableColumn name="bool">
        <span slot="header" style={{ color: 'red' }}>boolean</span>
    
        <template slot="cell">
          {({ row }) => <input type="checkbox" disabled defaultChecked={row.bool} />}
        </template>
      </TableColumn>
    
    </Table>
    Ответ написан
  • Как сделать dropdown в react?

    0xD34F
    @0xD34F Куратор тега React
    Ответ написан
    Комментировать
  • Как сделать toogle кнопок?

    0xD34F
    @0xD34F Куратор тега React
    isBlockNavButtons отвечает за логику disable для тех кнопок. То есть если у нас элемент последний или первый, то мы блочим нужную нам кнопку.

    А почему эта функция работает только в одну сторону - на блокировку? Пусть и обратную операцию тоже выполняет. Кроме того, работает она некорректно, если элемент всего один - в этом случае надо блокировать обе кнопки, но поскольку условия блокировки у вас зависимы, блокируется только одна.

    В общем, я бы заменил if-else на что-то такое:

    dispatch({
      type: `${CREATE_QUESTION}_BLOCK_BUTTON`,
      payload: {
        blockPreviousButton: elementIndex === 0,
        blockNextButton: elementIndex === data.length - 1,
      },
    });
    Ответ написан
    3 комментария
  • Как правильно обновить компонент в данном случае?

    0xD34F
    @0xD34F Куратор тега React
    Условие допустимости обновления должно быть чуть более сложным - при запрете надо допускать обновление в случае, если вы пытаетесь выполнить разблокировку, т.е:
    shouldComponentUpdate(nextProps, nextState) {
      return !this.state.updatesLocked || !nextState.updatesLocked;
    }
    Ответ написан
    6 комментариев
  • Как определить что пользователь имеет не сохраненные данные?

    0xD34F
    @0xD34F Куратор тега React
    Пусть данные будут представлены двумя экземплярами - первый пользователь редактирует, второй остаётся неизменным. При необходимости определить наличие изменений, внесённых пользователем - сравниваете попарно их свойства.
    Ответ написан
  • React.js, почему с первого раза не обновляется массив?

    0xD34F
    @0xD34F Куратор тега React
    Может кто-нибудь подсказать почему так происходит и как исправить?

    Отвечать на вопрос "почему" особого смысла нет - ерундой какой-то занимаетесь, все эти дополнительные массивы, кто вас этим глупостям научил?

    Как исправить - да выбросить всё лишнее на хрен, оставить один массив items, с ним и работать:

    class AddItems extends React.Component {
      state = {
        value: '',
        items: [],
      }
    
      inputChange = ({ target: { value } }) => {
        this.setState({ value });
      }
    
      addNewItem = () => {
        if (this.state.value) {
          this.setState({
            items: [ ...this.state.items, {
              text: this.state.value,
              id: (new Date()).getTime().toString(),
            } ],
            value: '',
          });
        }
      }
    
      render() {
        return (
          <div className="addItems">
            <div className="addSection">
              <input type="text" value={this.state.value} onChange={this.inputChange} />
              <input type="submit" onClick={this.addNewItem} />
            </div>
            <div className="listSection">
              <ul>{this.state.items.map((item) => <li key={item.id}>{item.text}</li>)}</ul>
            </div>
          </div>
        )
      }
    }
    Ответ написан
    2 комментария
  • Как спровоцировать re-render дочернего компонента?

    0xD34F
    @0xD34F Куратор тега React
    Добавьте в LibraryContent:

    componentDidUpdate(prevProps) {
      if (prevProps.url !== this.props.url) {
        this.getData();
      }
    }
    Ответ написан
    Комментировать
  • Как можно сделать выбор только одного тэга, в ant design - select?

    0xD34F
    @0xD34F Куратор тега React
    тег должен меняться,а не добавляться, как по дефолту сейчас

    Вообще-то, "по дефолту" - это как раз то, что вам нужно. Внимательнее изучайте документацию.
    Ответ написан
  • В чем ошибка в компоненте для копирования кода svg иконки в буфер обмена?

    0xD34F
    @0xD34F Куратор тега React
    Объект-то в строку надо превратить.

    Добавляете

    import ReactDOMServer from 'react-dom/server';

    в начало вашего index.js, затем

    textField.innerText = IconsList.internet;

    меняете на

    textField.innerText = ReactDOMServer.renderToStaticMarkup(IconsList.internet);
    Ответ написан
    Комментировать
  • Нормальное ли разделение компонентов?

    0xD34F
    @0xD34F Куратор тега React
    Нормальное ли разделение компонентов

    Вы бы показали что-нибудь более законченное... У вас там всего лишь 85 строк кода, а вы волнуетесь, хорошо ли компоненты выглядят. СЕРЬЁЗНО??!

    правильно ли делать такие передачи props??

    Сомнительно. Зачем вручную возиться с четырьмя значениями? Вдруг завтра надо будет сделать 5 или 8 или 23 - так и будете копипастить? Кладёте их в отдельный объект и работаете уже с этим объектом, типа так.
    Ответ написан
  • Почему не могу установить значение?

    0xD34F
    @0xD34F Куратор тега React
    Ну, косяк где-то в компоненте. Если обновить версию material-ui, всё будет OK.

    UPD. Вынесено из комментариев:

    Обновить не вариант, в проекте этот юзается(
    Слишком много надо будет переписывать

    Обновляйте не до последней версии тогда. Если верить чейнджлогу, этот баг был исправлен в версии 1.0.0-beta.22 (в вашем примере предыдущая, так что думаю, особых проблем не будет).
    Ответ написан
  • Как менять стили в зависимости от стейта в React?

    0xD34F
    @0xD34F Куратор тега React
    Так вы уже почти всё сделали сами... просто передавайте в кнопку isSelected, типа так.
    Ответ написан
    1 комментарий