Ответы пользователя по тегу React
  • Как при клике на элемент получить src и value дочерних элементов?

    Доставать что-то из ноды - это не совсем react-way (т.к. реакт инкапсулирует работу с DOM).

    Сделайте отдельный компонент под это дело:

    class ListItem extends React.PureComponent {
      handleClick = () => {
        const { src, label, onClick } = this.props
    
        return onClick(src, label)
      }
    
      render() {
        const { src, label, onClick } = this.props
    
        return (
          <li onClick={onClick && this.handleClick}>
            <img src={src} />
            <span>{label}</span>
          </li>
        )
      }
    }


    И передавайте в этот компонент нужные значения:

    <ListItem src="/uploads/0.png" label="Test" onClick={this.select} />
    Ответ написан
    Комментировать
  • Как делать server-side rendering React.js на php?

    Делайте на PHP rest API и отдельно ставьте nodejs для рендеринга фронтенда... и будет вам счастье!)
    Ответ написан
    Комментировать
  • Как вывести контекст нажатого компонента 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 комментариев
  • Как вывести дочерние элементы реакта без span?

    Какой у вас используется реакт? В 15й версии убрали лишние span элементы из дом.
    Ответ написан
  • Очистить input React/Redux?

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

    value={this.state.value}

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

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


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

    Если у вас роутер не 4й версии, то можно попробовать добавить к роутам свойство wrapperClass

    <Route path="/" component={App}>
      <Route path="list" component={ListComponent} wrapperClass="wrapper--list" />
    </Route>


    Идеологически, конечно, не очень хорошо мешать стили и конфигурацию роутов. Но зато: в своем компоненте App вы можете достать эти значения безо всяких редьюсеров\диспатчей:

    render() {
      // routes - это массив роутов для текущей локации
      // если взять за основу конфигурацию роутов, которую я привел выше,
      // то при переходе по пути /list в массиве будет два элемента.
      const { children, routes } = this.props
      const wrapperClass = (_.findLast(routes, route => !!route.wrapperClass) || {}).wrapperClass
      
      return (
        <div className={wrapperClass}>
          {children}
        </div>
      )
    }
    Ответ написан
  • React.js: В чем разница между State с типом Object и State с типом Array?

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


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

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

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

    ref используется когда нужна ДОМ-нода или реакт-элемент. Например, после какого-то события вы хотите ставить focus в какой-то инпут. Берете ref инпута и ставите фокус.

    В state - хранится локальное состояние.
    Ответ написан
    Комментировать
  • Библиотека асинхронных запросов для 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 комментария
  • Не доступен файл bundle.js (React/webpack)?

    Скорее всего у вас используется webpackDevMiddleware или webpackDevServer. В режиме разработки (dev) он создает эти файлы на лету.

    Если вам нужен откомпилированый бандл - собирайте проект с NODE_ENV = production
    Ответ написан
    3 комментария
  • Возможно ли застопорить удаление компонента в react?

    Можно использовать тот факт, что дочерние компоненты в реакте (children) передаются просто как props. Поэтому можно предварительно сохранять их в state (в конструкторе) и затем, при каждом обновлении компонента, в методе componentWillReceiveProps смотреть какие children были удалены и вызывать для них какой-нибудь метод (назовем его doDefferedUnmount). Пускай этот метод возвращает promise и когда promise выполнится (resolve\reject - не важно) - удалять этот children из нашего буфера в state. При этом рендерить мы будем не реальные props.children, а дочерние компоненты из нашего внутреннего буфера в state. Также нам понадобятся ссылки (ref) на элементы (которые уже отрендерены реактом) так как нам нужно будет вызвать метод doDefferedUnmount. А он должен вызываться только для инстансов (элементов, а не компонентов: компонент - это класс).

    // Я удалил все лишнее
    class DelayedContainer extends React.PureComponent {
      constructor(props, context) {
        super(props, context)
        
        this.chidrenRefs = {}
        this.state = {
          childrenStore: this.childrenArrToStore(React.Children.toArray(props.children))
        }
      }
    
      removeChidren = (key) => {
        const { childrenStore } = this.state
    		
        this.chidrenRefs = _.omit(this.chidrenRefs, key)
        this.setState({
        	childrenStore: _.omit(childrenStore, key)
        })
      }
    
      handleChildRef = (node, key) => {
        this.chidrenRefs[key] = node
      }
    
      render() {
        const { childrenStore } = this.state
    	
        return (
        	<div>
            {_.values(childrenStore).map(child => {
            	return React.cloneElement(child, { ref: node => this.handleChildRef(node, child.key) })
            })}
          </div>
        )
      }


    // Компонент, который будем удалять с задержкой
    // обратите внимание на метод doDefferedUnmount 
    // именно его мы будем вызывать
    class SomeItem  extends React.PureComponent {
      doDefferedUnmount = () => {
        console.log('doDefferedUnmount for ', this.props.word);
        return new Promise(resolve => setTimeout(resolve, 200))
      }
    
      handleClick = e => {
        const { id, onClick } = this.props
        return onClick && onClick(id, e)
      }
    
      render() {
        const { word } = this.props
    
        return (
        	<button type="button" onClick={this.handleClick}>{word}</button>
        )
      }
    }


    Рабочий пример кода - https://jsfiddle.net/jwm6k66c/1884/ . Элементы удаляются через 200мс после нажатия. Но я правда не знаю зачем вам это надо, так как при этом никак нельзя адекватно сделать функционал :
    Компонент не удалялся из DOM и с ним можно было работать, выполнять какие-то функции и только когда моя функция возвращает true он удалял его из dom


    Так как это не react-way. Вы мыслите другими подходами и библиотеками. В реакте вы берете redux (flux/...) и храните данные в хранилище (store), если вам нужно удалить какие-то данные (а объекты в DOM - это отображение данных) - отправляете запрос на сервер и в случае успеха диспатчите экшен (действие) на удаление данных из хранилища... и на следующем рендере нужные элементы удалятся, либо можно будет вывести сообщение об ошибке.


    PS Пример кода я привел только для ознакомления с возможностями react. Я крайне не рекомендую использовать его для того, о чем говорит автор вопроса!
    Ответ написан
  • Как правильно подключить React к сайту?

    Правильно было бы установить node, npm, webpack и сделать сборку проекта в один файл: она содержала бы этап трансляции "нового" js в старый.

    Если вы хотите на лету обрабатывать код, то вам нужно подключить babel-standalone (вы это уже сделали). Но упустили один момент из документации:

    <script type="text/babel" src="foo.js"></script>

    Для скриптов, которые вы хотите автоматически компилить babel'ом надо указывать атрибут type = text/babel.
    Ответ написан
    Комментировать
  • Как создать пустое backend приложение для NodeJS с поддержкой WebPack + ReactJS + ES6?

    Для поддержки реакта в nodejs вам по большому счету не нужен вебпак. Ставте babel, потом сделайте точку входа серверную на подобии https://github.com/erikras/react-redux-universal-h...

    //  enable runtime transpilation to use ES6/7 in node
    
    var fs = require('fs');
    
    var babelrc = fs.readFileSync('./.babelrc');
    var config;
    
    try {
      config = JSON.parse(babelrc);
    } catch (err) {
      console.error('==>     ERROR: Error parsing your .babelrc.');
      console.error(err);
    }
    
    require('babel-register')(config);


    И после подключайте ваш серверный код (https://github.com/erikras/react-redux-universal-h...

    Зависимостей понадобится примерно столько https://github.com/erikras/react-redux-universal-h... (смотря какой у вас будет конфиг\пресет для babel)
    Ответ написан
    3 комментария
  • Возможно ли в react-компонентах использовать микс классов по БЭМ?

    Если я вас правильно понял:

    class Avatar extends React.Component {
      render() {
        const finalClassName = 'avatar ' + (this.props.className || '')
        return (
          <img className={finalClassName} src={this.props.user.avatarUrl} alt={this.props.user.name} />
        );
      }
    }
    
    
    class UserInfo extends React.Component {
      render() {
        return (
          <div className="user-info">
            <Avatar className="user-info__avatar" user={this.props.user} /> 
            <div className="user-info__name">{this.props.user.name}</div>
          </div>
        );
      }
    }


    Т.е. просто передавайте className как props компоненту Avatar, затем объединяйте в один классНейм:
    // выражение в скобочках нужно, чтобы не получилось 'avatar undefined', когда className не передан.
    // Я рекомендую указать className, равное '', в defaultProps компонента Avatar
    const finalClassName = 'avatar ' + (this.props.className || '')


    Также в npm есть удобный пакет https://www.npmjs.com/package/classnames , который позволяет формировать строку с классами. Ваш пример выглядел бы так:

    const finalClassName = classnames({
      'avatar': true,
      [this.props.className]: !!this.props.className,
      'some-other-class': someCondition
    })
    Ответ написан
    6 комментариев
  • Как сделать авторизацию в react.js?

    Вполне хорошее решение - проверять права доступа в onEnter. А для чего вам понадобились кукис (касаемо авторизации)? Токены лучше всего хранить в localstorage и синхронизировать с вашим store.

    Сгруппируйте роуты, для которых нужна авторизация и ставьте коллбэк туда:
    <Route path="/" component={App}>
      <Route onEnter={checkAuth}>{/* Auth routes */}</Route>
      {/* Home page route */}
      <IndexRoute component={Home}>
      {/* Other public routes /*}
      <Route path="about" component={AboutPage} />
    </Route>
    Ответ написан
    5 комментариев
  • Как работает mapStateToProps в Redux?

    В mapStateToProps есть проверка - "Изменились ли props?": если да - компонент обновляется, если нет - не обновляется.

    В вашем случае, вполне возможно, что-то еще вызывает ререндер компонента А... приведите больше кода.
    Ответ написан
    Комментировать