Ответы пользователя по тегу JavaScript
  • Нужно ли выполнять сборку проекта для production (node/express)?

    Если API идет как полностью отдельный код и вы используете только те фичи JS, которые поддерживаются текущей версией nodejs - то ничего особо не нужно делать.. Ставите зависимости и запускаете.

    Для server-rendera скорей всего придется билдить приложение, чтобы нормально оттранслировать jsx и прочие импорты.
    Ответ написан
    4 комментария
  • Как лучше работать с массивом данных?

    Это обычный рекурсивный обход дерева. Добавление\удаление\редактирование будет зависеть от того как (и где) вы храните данные - flux\redux\whatever. В случае с редаксом - я бы хранил в state дерево в плоском виде (вам нужны будут id, но, думаю, что с монго - это не проблема).

    Отображать дерево можно так:

    const MySuperTree => (props) => (
      <ul>{props.nodes.map(node => <TreeNode {...node} />)}</ul>
    )
    
    class TreeNode extends PureComponent { 
      render() {
        const { name, val1, val2, nodes } = this.props
        return (
          <li>
            <b>{name}  | {val1} | {val1+getValFromChild(childs)} {val2}</b>
            {nodes && nodes.length > 0 && (
              <MySuperTree nodes={nodes} />
            )}
         </li>
        )
      }
    }
    Ответ написан
    6 комментариев
  • Как проверить размеры картинки до ее отрисовки в dom?

    После того, как компонент будет добавлен в DOM - берем src из props и создаем новый DOM-элемент img, ставим обработчик onLoad и загружаем картинку. Затем проверяем размеры и устанавливаем стейт

    class Cover extends Component { 
       state = {
         loaded: false,
         width: 0,
         height: 0,
       }
    
       componentDidMount() {
         const img = document.createElement('img')
    
         img.onload = e => {
           console.log('image loaded', img.width, img.height)
           this.setState({ loaded: true, width: img.width, height: img.height })
         }
    
         img.src = this.props.src
       }
    
      renderLoading() {
        return <div>loading... </div>
      }
      
      renderLoaded() {
        const { width, height } = this.state
        const isFits = width === 140 && height === 205
        return isFits
          ? <div>обложка успешно установлена</div>
          : <div>Обложка должна быть 140х205</div>
      }
    
       render() {
           return this.state.loaded ? this.renderLoaded() : this.renderLoading()
       }
    }
    Ответ написан
    Комментировать
  • Можно ли на ReactJS динамически загружать компоненты без знания о них при сборке самого приложения (как это реализовано в Angular 2+)?

    Динамически подгружать компоненты? Это не к реакту, это к вашему сборщику.
    В последних вебпаках (2+) есть поддержка динамических импортов:

    import('moduleName').then(module => /* do something */)


    Ну и дальше вы сможете сохранить этот модуль (например в state):
    class Bundle extends Component {
      state = {
        // short for "module" but that's a keyword in js, so "mod"
        mod: null
      }
    
      componentWillMount() {
        this.load(this.props)
      }
    
      componentWillReceiveProps(nextProps) {
        if (nextProps.load !== this.props.load) {
          this.load(nextProps)
        }
      }
    
      load(props) {
        this.setState({
          mod: null
        })
        props.load((mod) => {
          this.setState({
            // handle both es imports and cjs
            mod: mod.default ? mod.default : mod
          })
        })
      }
    
      render() {
        return this.state.mod ? this.props.children(this.state.mod) : null
      }
    }
    
    export default Bundle


    А вызывать все это дело вот так:
    <Bundle load={() => import('./something')}>
      {(mod) => ()}
    </Bundle>


    Но это все в рамках проекта - добавили новый компонент - пересобрали проект. И это самая адекватная (на мой взгляд) практика. Случаи, конечно, бывают разные - но мне как-то уютнее, когда я знаю, что весь нужный код находится у меня в проекте, а не где-то там. Я имею ввиду в первую очередь зависимости ваших динамических компонентов (в первом ангуляре была своя система DI и свой подход к разработке, но с тех пор уже много воды утекло и нативные JS модули, очевидно, гораздо лучшее решение). Конечно, теоретически - можно напридумывать костылей и грузить их откуда угодно...
    Ответ написан
  • Как в REACT-REDUX сделать, чтобы перерендеривался только один элемент?

    Гляньте вот этот ответ React-Redux. Какой путь правильнее: вызов connect ...

    Если кратко:
    • Избавьтесь от коннектов, которые слушают большие куски стейта
    • Используйте reselect, для вычислений стейта (например, когда собираете элемент из разных редьюсеров)
    • Используйте connect элементах, которым нужны данные. Их может быть много. Список из 1000 connected-elements работает быстрее, чем список из 1000 элементов с 1м connected-element. Потому что даже PureComponent имеет свой оверхед и если дочерний компонент не обновился - это не значит, что diff алгоритм реакта не будет обрабатывать изменения в родительском компоненте
    Ответ написан
    2 комментария
  • Как реализовать динамический import для code splitting в Webpack 2?

    UPD2: Решение проблемы
    У вас есть название entryPoint и именно его нужно указать как name при конфигурации commonChunksPlugin
    entry: {
        application:  /* ... */
      },
    ....
    plugins: {
      new webpack.optimize.CommonsChunkPlugin({
          name: 'application', // <--- Так же как и entryPoint
          async: "vendors", // <--- будет использовано как имя файла (можно оставить просто true). "vendors.js"
          children: true,
          minChunks: 2 // <--- должно быть >= 2
        })
    }


    Похоже, что это issue. Обсуждение идет тут -https://github.com/webpack/webpack/issues/5109#iss...

    OLD:
    старый ответ
    По-идее у вас должно быть что-то такое:

    {
      entry: {
        main: './reactStartup.js'
      },
      output: {
        filename: '[name]-bundle.js',
        chunkFilename: '[name]-chunk.js',
        path: path.resolve(__dirname, 'dist'),
        publicPath: 'dist/'
      },
      plugins: [
        new webpack.optimize.CommonsChunkPlugin({
          async: true,
          children: true,
          minChunks: 2,
        }),
      ]
    }


    Обратите внимание на minChunks по-умолчанию там скорей всего Inf (документация), а это значит, что в этот чанк ничего не попадает.

    Но CommonsChunkPlugin просто выделяет общие модули (которые используются >= 2х раз), а для динамических импортов вам нужен отдельно плагин для babelrc:
    // .babelrc
    {
      "plugins": [
        "syntax-dynamic-import"
      ]
    }


    UPD1
    Еще дело может быть в модулях - я с вебпаком2 давно отключил преобразование модулей в babel ( "modules": false):
    "presets": [
        [
          "env",
          {
            "targets": {
              "node": "current",
              "browsers": "last 2 versions"
            },
            "modules": false,
            "loose": true
          }
        ],
        "react",
      ],
    Ответ написан
  • Как получить данные JSON?

    На чистом JS - у браузеров уже давно есть fetch api:

    fetch('http://country.io/names.json')
      .then(r => r.json())
      .then(names => console.log('Names arrived!', names)


    Узнать больше можно из документации:

    Ну и про CORS не забывайте - если сервер не вернет эти заголовки, то запрос на другой домен не пройдет.
    Ответ написан
    Комментировать
  • В чем преимущество TypeScript перед Flow?

    Эта информация, мягко говоря, не соответствует действительности:

    1. Хабр: Flow + tcomb = типизированный JS
    2. Type Systems for JavaScript - тут конкретно сравниваются flow и typescript. Отлично видно недостатки последнего.


    Плюс ко всему - если вы реакт разработчик, то вам скорее подойдет flow - т.к. он от фейсбука, что гарантирует нормальную его работу с реактом.
    Ответ написан
    2 комментария
  • Как вывести контекст нажатого компонента React?

    Хочу дополнить ответ juicyigor т.к. он содержит одну критическую (для производительности) ошибку:

    <First 
      city={data.city} 
      handleClick={this.handleClick(data.city)} 
    />


    handleClick = city => () => {
      this.setState({
        selectedCity: city,
      });
    };


    Суть в том, что мы при каждом рендере создаем новый коллбэк и передаем его как prop компоненту First. Во-первых: даже без реакта у вас могут возникнуть проблемы со сборщиком мусора, если вы достаточно часто делаете ререндер. Во-вторых: хорошей практикой для компонентов-представлений (глупых компонентов - dump components) является использование так называемого pure render (путем наследования класса компонента от React.PureComponent). Это дает нам возможность ререндерить (обновлять) компонент только в том случае, если props или state изменились. У Вас в компоненте First state не используется, значит, рендер компонента будет зависеть только от props, но при этом - при каждом рендере родительского компонента вы передаете в First новый экземпляр handleClick. Значит - компонент First будет каждый раз рендерится, даже если по сути - данные не поменялись. Это плохо и является антипаттерном. Предлагаю вот такой вариант:

    class First extends React.PureComponent {
      handleClick = () => {
        const { onClick, city } = this.props
    
        return onClick(city)
      }
    
      render() {
        const { onClick, city } = this.props
    
        return (
          <div className="first">
            <button onClick={onClick && this.handleClick}>
              click
            </button>
            <p>{city}</p>
          </div>
        )
      }
    }


    В компонент First я добавил метод handleClick, который вызывает коллбэк onClick (который передан через props) и передает туда city. Таким образом мы избавились от пересоздания коллбэка в рендере родительского компонента. Также обратите внимание на определение этого метода:

    handleClick = () => {

    Такая запись подразумевает в себе автобиндинг: т.е. this у вас будет ссылаться именно на ваш элемент.

    И небольшое замечание по названиям: handleSomething - это функция, которую вы передаете в свойство с названием onSomething. Пример:
    <input onBlur={handleBlur} />

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

    class TestComponent extends React.PureComponent{
      constructor() {
        super();
        this.state = {
          selectedCity: false,
        };
      }
      
      handleClick = city => {
        this.setState({
          selectedCity: city,
        });
      };
      
      render() {
        return (
          <div>
            {locations.map((data, i) => 
              <First 
                city={data.city} 
                onClick={this.handleClick} 
              />
            )}
            <Second city={this.state.selectedCity} />
          </div>
        );
      }
    }


    PS саму логику я не трогал, просто хотел обратить Ваше внимание на ошибки.
    Ответ написан
    3 комментария
  • Не могу понять как убрать элемент (Или вернуться к InItialState "Если такое возможно")?

    Почему не используете классы?

    const emptyContacts = {
      address: '' ,
      email: '',
    }
    
    var Contact = React.createClass({
        getInitialState: function() {
          return {
           contactData: emptyContacts,
          }
        },
        toggleContactsData: function(event) {
            this.setState({
                contactData: thsi.state.contactsData === emptyContacts
                  ? { address: this.props.address, email: this.props.email, }
                  : emptyContacts
            });
        },
    
        render:function() {
          return (
            <li className="contact" onClick={this.toggleContactsData}>
              <img className="contact-image" src={this.props.image} width="68px" height="68px"/>
              <div className="contact-info">
                <div className="contact-name" >{this.props.name}</div>
                <div className="contact-number" >{this.props.phoneNumber}</div>
                <div>{this.state.contactData.address}</div>
                <div>{this.state.contactData.email}</div>
              </div>
            </li>
          )
    
        }
      });
    Ответ написан
    3 комментария
  • Как генерировать динамическое количество компонентов в React?

    Сделайте компонент ItemsList и Item:

    class Item extends React.PureComponent {
      render() {
        const { name, color } = this.props
    
        return (
          <li>
             <b>{name} ({color})</b>
          </li>
        )
      }
    }
    
    
    class ItemsList extends React.PureComponent {
      render() {
        const { items } = this.props
    
        return (
          <ul>
            {items.map(item => (
              <Item key={item.id} {...item} />
            )}
          </ul>
        )
      }
    }


    Тут обратите внимание на свойство key - оно необходимо, когда у вас используются динамические children.
    Ответ написан
    Комментировать
  • Как организовать взаимодействие компонентов в React?

    Я пометил при вызове компонента его ref'ом и пнул его setState()


    Так делать не стоит. setState: это все-таки внутренний метод компонента. Просто делайте rerender с новым массивом.

    как правильно отследить клик по селектору? Передавать callback и в props компонента его обрабатывать?


    Да, из родителя передавайте prop onClick и его уже вешайте на нужные компоненты.
    Ответ написан
    5 комментариев
  • Очистить input React/Redux?

    Вы в компоненте Input используете state в качестве значения input'а:

    value={this.state.value}

    При этом: вы также используете state родительского компонента и очищаете именно его:

    addTodo() {
            // ...
            this.setState({todoName: ''});
        }


    Т.е. Вам нужно: либо использовать props.value в компоненте инпута, либо (в нем же) реализовать механизм передачи значения из props в state.
    Ответ написан
    2 комментария
  • React.js: В чем разница между State с типом Object и State с типом Array?

    let newState = Object.assign(state, {messages:action._data, loading:false});


    В вашем случае вы мутируете объект state. А реакт (и экосистема) построена в функциональных парадигамах, одна из которых - иммутабельность. Т.е. мы берем предыдущий state, новый state и просто сравниваем их по ссылке:

    newState === state // true в вашем случае

    В вашем случае - state мутировал, но это все еще одна и та же ссылка и реакт\редакс думает, что никаких изменений не было. Как правильно вам уже подсказал Aves
    Ответ написан
    Комментировать
  • Библиотека асинхронных запросов для react?

    Да, такая библиотека есть. Проблема в том, что в JS нативные промисы (Promise) нельзя отменить (not cancelable)... но при этом - у нас есть генераторы, которые вполне себе позволяют имитировать отмену выполнения какой-либо функции, скажем, в середине.

    Для того, чтобы все заработало - вам нужно использовать связку из любой понравившейся библиотеки для непосредственно запросов (я предпочитаю isomorphic-fetch), затем взять redux и middleware для него (редакса) - redux-saga.

    Если вы не знакомы с экосистемой редакса или первый раз слышите про redux-saga - прочтите документацию, посмотрите уроки. Если вкратце - библиотека построена на генераторах. Функция-генератор возвращает итератор и ее выполнение прекращается каждый раз, когда мы возвращаем итератору новое значение (yield)

    Ниже продемонстрирую как это примерно работает:

    function* myCancelableAction(someData) {
      // вернет итератору промис и приостановит работу функции до следующего вызова next
      // в нашем случае - функция продолжит выполнение, когда придет ответ сервера
      const response = yield doAjaxRequest(someData) 
      yield dispatchSuccessAction(response)
    }
    
    const action = myCancelableAction();
    const promise = action.next().value // fetch promise
    
    promise.then(response => {
      // если новых запросов не поступило
      if(!newRequestIsComing) {
        // мы можем передать значение в нашу функцию (через next)
        console.log(action.next(response).value); // dispatched action
      }
    })


    Таким образом, после того, как функция вернула значение первый раз, применительно к теме поста это будет "сделай AJAX-запрос", мы можем не выполнять ее дальше (если захотим). Отменить ajax запрос в этом случае не получится, но мы можем просто не учитывать его результаты (не диспатчить success-экшен, например).

    UPD1 обновил пример кода
    Ответ написан
    Комментировать
  • Как динамически добавить компонент в React?

    Сделайте под это дело отдельный компонент. Никаких appChild - это реакт.

    class MyClickableComponent extends React.PureComponent {
      construct(props, context) { 
        super(props, context)
    
        this.state = {
          isOpen: false,
        }
      }
    
      handleClick = e => {
        this.setState({ isOpen: true })
      }
    
      render() {
       const { isOpen } = this.state
    
        return (
          <div>
            <div onClick={this.handleClick }>click on me</div>
            {isOpen && (
              <b>opened!</b>
            )}
          </div>
        )
      }
    }


    ReactDOM.render(
            <div>
                <Month />
                       <MyClickableComponent  />
                <Content />
            </div>,
      document.getElementById('root')
    );
    Ответ написан
    3 комментария
  • React + Redux vs Angular 2?

    Интересует вопрос, что лучше подойдет для этого? Знаю , что angular2 в разы превосходит react по производительности, но большинство "хейтят" ангулар и идут в сторону React

    Сравнение производительности
    фреймворков


    затем обращаться к компонентам react ( возможно ли обратиться извне? )

    Не совсем понятно, что вы имеете ввиду по "обращением к компоненту". Реакт позволяет вытащить DOM ноду по ref - документация

    В планах создать социальную сеть.
    Интересует вопрос, что лучше подойдет для этого?

    я бы посоветовал машину времени :)
    Ответ написан
    Комментировать
  • Как правильно обратиться к вложенному обьекту?

    Вам нужно последовательно пересоздать все вложенные объекты:

    return { 
      ...state,
      user: {
        ...state.user,
        response: { ...action.payload },
      }
    }
    Ответ написан
    1 комментарий
  • Как правильно создать структуру приложения на ReactJS + Laravel 5.3?

    На бэкенде: делаете rest-api с помощью Laravel.
    На фронтенде: берете реакт + редакс и разрабатываете приложение, которое будет общаться бэком через АПИ.
    Ответ написан
    Комментировать