2016-02-19 5 views
1

Я ищу для создания одностраничного приложения с ReactJS._React Js одностраничное приложение

Целесообразно ли комбинировать его с угловым или подходит только по себе? Я хотел бы, чтобы заполнить сайт на одну страницу с разделами - добавление различных функций, таких как каруселей, ползунки, изотопных фильтры ...

<!DOCTYPE html> 
<html> 
    <head> 
    <title>React Js one page</title> 

    <script src="https://fb.me/react-with-addons-0.14.7.min.js"></script> 
    <script src="https://fb.me/react-dom-0.14.7.min.js"></script> 
    </head> 

    <body> 
    <section> 
    One 

     <script> 
     var HelloMessage = React.createClass({ 
      render: function() { 
      return <div>Hello {this.props.name}</div>; 
      } 
     }); 

     ReactDOM.render(<HelloMessage name="Colonel Mustard" />, mountNode); 
     </script> 

    </section> 

    <section> 
     Two 


     <script> 

     var CommentBox = React.createClass({ 
      render: function() { 
      return (
       <div className="commentBox"> 
       Hello, world! I am a CommentBox. 
       </div> 
      ); 
      } 
     }); 
     ReactDOM.render(<CommentBox />, mountNode); 
     </script> 


    </section> 

    <section> 
     Three 

     <script> 
     "use strict"; 

     var MarkdownEditor = React.createClass({ 
     displayName: "MarkdownEditor", 

     getInitialState: function getInitialState() { 
      return { value: 'Type some *markdown* here!' }; 
     }, 
     handleChange: function handleChange() { 
      this.setState({ value: this.refs.textarea.value }); 
     }, 
     rawMarkup: function rawMarkup() { 
      return { __html: marked(this.state.value, { sanitize: true }) }; 
     }, 
     render: function render() { 
      return React.createElement(
      "div", 
      { className: "MarkdownEditor" }, 
      React.createElement(
       "h3", 
       null, 
       "Input" 
      ), 
      React.createElement("textarea", { 
       onChange: this.handleChange, 
       ref: "textarea", 
       defaultValue: this.state.value }), 
      React.createElement(
       "h3", 
       null, 
       "Output" 
      ), 
      React.createElement("div", { 
       className: "content", 
       dangerouslySetInnerHTML: this.rawMarkup() 
      }) 
     ); 
     } 
     }); 

     ReactDOM.render(React.createElement(MarkdownEditor, null), mountNode); 
     </script> 

    </section> 


    </body> 

</html> 
+0

Какую добавленную стоимость вы получаете, введя как Angular, так и ReactJS? – christopher

+0

Ну, мне было просто интересно, потому что Reacjs похож на вид. В то время как у Angular есть контроллер просмотра модели и т. Д., Просто глядя, чтобы структурировать код хорошо –

+0

У меня есть этот jsfiddle, но он получил ошибку и не передавал реагирующие компоненты. Что не так? https://jsfiddle.net/5syaz4La/2/ –

ответ

6

Если вы только начинаете с Реагировать, я настоятельно рекомендую следующие Pete Hunt's advice:

Вы будете знать, когда вам нужно Flux. Если вы не уверены, что вам это нужно, вам это не нужно.

Лучшее, что нужно сделать, это начать с Реагирования самостоятельно и управлять состоянием приложения, используя локальный state, который поставляется с каждым из ваших компонентов.

Когда вы обнаружите, что вам придётся передать данные обратно родительским компонентам, добавьте Flux в микс и перепишите свои компоненты с состоянием, чтобы вместо этого использовать магазины Flux.

Мы рассмотрим, как решить написать упрощенную версию компонента ответа StackOverflow в качестве приложения React снизу вверх.

Заметьте, я сказал Реагировать приложение, не Реагировать компонент. Это потому, что нет технических различий. Приложение React - это большой компонент React, состоящий из множества меньших.

идентификации компонентов

После того, как у вас есть интерфейс для приложения (что-нибудь из каркасных в HTML/CSS) вы можете визуально подразделить их на работу, как они подходят друг к другу, как Реагировать компоненты.

Нет никаких жестких и быстрых правил о том, как именно вы решаете, что должно или не должно быть его собственным компонентом, но вы почувствуете это больше, когда вы это сделаете.

  • является <Answer />
    • является <Votes />
    • является <AnswerText />
    • является <AnswerActions />

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

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

Мы можем использовать синтаксис компонента без состояния, чтобы начать работу с идентифицированными компонентами. Вот пример того, как мы могли бы написать компонент <Votes />.

function Votes() { 
    return (
    <div> 
     <a>▲</a> 
     <strong>0</strong> 
     <a>▼</a> 
    </div> 
); 
} 

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

Мы можем сделать это в DOM, чтобы проверить, что он работает в любое время.

ReactDOM.render(<Votes />, document.getElementById('app')); 

После того, как вы завершили реализацию статических версий других компонентов, вы можете поместить их вместе, чтобы создать родитель <Answer /> компонента.

function Answer() { 
    return (
    <div> 
     <Votes /> 
     <AnswerText /> 
     <AnswerActions /> 
    </div> 
); 
} 

потока данных Дизайн

Следующая вещь, которую нужно сделать, это выяснить, как потоки данных через приложения.

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

{ 
    "id": 0, 
    "votes": 0, 
    "text": "This is an answer" 
} 

Первоначально мы можем оказать <Answer /> составляющую, передавая этот объект ответа на него в качестве опоры ,

<Answer answer={answer} /> 

Теперь это то, что компоненты выполняют передачу соответствующих данных своим детям.

Очевидно, что не каждому ребенку нужны все данные, поэтому нам нужно будет решить, какие данные идут туда. Давайте обновим наш компонент <Answer />.

function Answer(props) { 
    var answer = props.answer; 
    return (
    <div> 
     <Votes id={answer.id} count={answer.votes} /> 
     <AnswerText text={answer.text} /> 
     <AnswerActions id={answer.id} /> 
    </div> 
); 
} 
  • The <Votes /> потребности компонентных знать текущее количество голосов, и он также должен знать id ответа, так что он может общаться изменения на сервер.

  • Компонент <AnswerText /> просто отображает блок текста, так что это все, что нам нужно передать.

  • Наконец, компонент <AnswerActions /> отображает список ссылок, которые позволяют пользователю выполнять какое-либо действие (обмениваться, редактировать, отмечать) в ответе. Этот компонент также нуждается в ответе id, чтобы он мог связываться с сервером.

Теперь мы должны обновить эти дочерние компоненты в свою очередь, чтобы использовать эти новые динамические значения вместо статических значений, которые мы использовали вначале. Мы рассмотрим компонент <Votes />, чтобы это произошло.

function Votes(props) { 
    var urls = { 
    upvote: '/api/answers/' + props.id + '/upvote', 
    downvote: '/api/answers/' + props.id + '/downvote' 
    }; 

    return (
    <div> 
     <a href={urls.upvote}>▲</a> 
     <strong>{props.votes}</strong> 
     <a href={urls.downvote}>▼</a> 
    </div> 
); 
} 

Теперь наш компонент голосования будет сделать запрос HTTP на соответствующую конечную точку, когда мы нажимаем на кнопках голосования, однако, мы бы лучше сделать это обновление без перезагрузки и повторного рендеринга всего приложения.

Идентифицировать Stateful Компоненты

Заключительная часть процесса разработки компонента, чтобы идентифицировать компоненты с сохранением состояния. Эти компоненты имеют движущиеся части и данные, которые будут меняться в течение всего срока службы приложения.

Каждый раз, когда состояние внутри компонента изменяется, весь компонент повторно отображается. Мы можем пересмотреть каркасы, чтобы увидеть, какие из наших компонентов должны управлять изменяющимися данными.

Это приложение имеет только один компонент с сохранением состояния (), и это `. Когда мы нажимаем на одну из стрелок, нам нужно обновить номер, чтобы отобразить новый счетчик.

Это единственный из наших компонентов, который когда-либо нуждается в повторной обработке.

Это означает, что нам нужно будет обновить компонент, чтобы использовать синтаксис React's createClass. Это позволяет ему управлять своим собственным состоянием.

var Votes = React.createClass({ 
    getInitialState: function() { 
    return { votes: this.props.votes }; 
    }, 
    upvote: function() { 
    var newVotes = this.state.votes + 1; 

    this.setState({ 
     votes: newVotes 
    }); 
    }, 
    downvote: function() { 
    var newVotes = this.state.votes - 1; 

    this.setState({ 
     votes: newVotes 
    }); 
    }, 
    render: function() { 
    return (
     <div> 
     <a onClick={this.upvote}>▲</a> 
     <strong>{this.state.votes}</strong> 
     <a onClick={this.downvote}>▼</a> 
     </div> 
    ); 
    } 
}); 

Я немного подпрыгнул из пушки и внедрил полный компонент, но, надеюсь, вы получите эту идею.

  • Сначала мы используем getInitialState создать какое-то состояние, чтобы представить начальное число голосов в компоненте.

  • Далее мы реализуем и downvote методы компонентов, которые обновляют состояние компонента.

  • Наконец, мы повторно реализуем метод рендеринга ранее, но стрелки запускают новые методы компонентов, а не запросы страниц.

Каждый раз, когда мы делаем вызов setState, React будет повторно вынести компонент. Надеюсь, вы можете понять, почему мы помещаем состояние в компонент <Votes />, а не в компонент <Answer />. Было бы безумным перерисовать текст ответа и действия, только потому, что голоса изменились.

Flux It Up

После того, как мы определили и реализовать все наши сохраняющих состояние компонентов, мы можем начать двигаться их состояние вне в Flux магазинах.

Скорее всего, что реальное приложение будет иметь <AnswerStore />, чем <VoteStore />, так что это будет реализовано нами. На данный момент мы просто будем насмехаться над нашими данными.

var AnswerStore = { 
    _listeners: [], 
    _answers: { 
    "0": { 
     "id": 0, 
     "votes": 0, 
     "text": "This is an answer" 
    } 
    }, 
    get: function(id) { 
    return this._answers[id]; 
    }, 
    update: function(id, update) { 
    var answer = this.get(id); 
    var updatedAnswer = Object.assign({}, answer, update); 
    this._answers[id] = updatedAnswer; 
    this.emit(); 
    }, 
    listen: function(f) { 
    this._listeners.push(f); 
    }, 
    emit: function() { 
    this._listeners.forEach(function(f) { 
     f(); 
    }); 
    } 
}; 

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

Важно, чтобы наш метод update рассматривал индивидуальные ответы как неизменяемые в этом приложении, в противном случае мы рискуем изменить объект, к которому ссылаются другие части приложения, в результате чего объект изменяется под ними. Мы используем Object.assign для создания нового объекта каждый раз, исходя из старого.

Следующее, что нам нужно сделать, это настроить некоторые обработчики действий для этого магазина.

dispatcher.register(function(action) { 
    switch(action.type) { 
    case 'UPVOTE': 
     var votes = ActionStore.get(action.id); 
     ActionStore.update(action.id, { votes: votes + 1 }); 
     break; 
    case 'DOWNVOTE': 
     var votes = ActionStore.get(action.id); 
     ActionStore.update(action.id, { votes: votes - 1 }); 
     break; 
    } 
}); 

Это просто провода метод обновления для двух действий, называемых 'UPVOTE' и 'DOWNVOTE'

Теперь мы связываем Flux нашего <AnswerComponent /> который должен быть переписано в длинной форме.

var Answer = React.createClass({ 
    getInitialState: function() { 
    return { answer: {} }; 
    }, 
    componentWillMount: function() { 
    this.update(); 
    AnswerStore.listen(this.update); 
    }, 
    update: function() { 
    var id = this.props.id; 
    this.setState({ answer: AnswerStore.get(id) }); 
    }, 
    render: function() { 
    var answer = this.state.answer; 
    return (
     <div> 
     <Votes id={answer.id} count={answer.votes} /> 
     <AnswerText text={answer.text} /> 
     <AnswerActions id={answer.id} /> 
     </div> 
    ); 
    } 
}); 

В нашем componentWillMount методе мы извлекаем наши исходные данные для магазина, а затем настроить слушатель на магазине, который извлекает и обновляет состояние компоненты, при изменении магазина.

И, наконец, нам нужен способ отправки соответствующих действий с нашего компонента <Votes />.

Самый популярный способ сделать это с создателями действий. Создатель действия - это функция, которая принимает некоторые данные в качестве параметров, затем упаковывает их и отправляет их как действие.

var Actions = { 
    upvote: function(id) { 
    dispatcher.dispatch({ 
     type: 'UPVOTE', 
     id: id 
    }); 
    }, 
    downvote: function(id) { 
    dispatcher.dispatch({ 
     type: 'DOWNVOTE', 
     id: id 
    }); 
    } 
}; 

Тогда мы называем эти действия внутри нашего <Votes /> компонента (который может стать лицом без гражданства снова).

function Votes(props) { 
    var id = props.id; 

    return (
    <div> 
     <a onClick={Actions.upvote.bind(null, id)}>▲</a> 
     <strong>{props.votes}</strong> 
     <a onClick={Actions.downvote.bind(null, id)}>▼</a> 
    </div> 
); 
} 

Этот компонент теперь использует создателей действия для отправки действий для нашего хранилища (ов) Flux.

Если мы посмотрим на поток данных через наше приложение, мы можем видеть, что мы имеем теперь однонаправленный цикл, а не дерево.

  • <Answer /> компонент проходит id вниз к <Votes /> компонента.
  • Компонент <Votes /> отправляет уведомление об этом, используя id.
  • AnswerStore обрабатывает действие и испускает изменение.
  • Компонент <Answer /> слышит обновление и обновляет его состояние, перерисовывая его дочерние элементы.

Это jsfiddle этой демонстрационной заявки.

Scale Up

Это очень простой компонент, который обрабатывает только небольшое количество потоков данных и даже меньше состояния приложения, однако, этого достаточно, чтобы показать вам, как составить Реагировать компонент, и это все, что вам нужно создайте приложение React.

Предположим, мы применяли вопрос StackOverflow как приложение React.

function App() { 
    return (
    <Page> 
     <Navigation /> 
     <SideBar> 
     <MetaDetails /> 
     <Ads /> 
     <RelatedQuestions /> 
     </SideBar> 
     <Question /> 
     <AnswerList /> 
     <AnswerEditor /> 
     <Footer /> 
    </Page> 
); 
} 

Это может показаться сложной приложения, но вы можете разбить его и выразить его в качестве отдельных компонентов, то вы можете реализовать и протестировать компоненты по отдельности, так же, как мы делали здесь и привести их в целом, чтобы сформировать комплексное применение.

Не Над осложнять

Для наиболее простых Реагировать приложения, такие как этот, поток не на самом деле необходимо. Стоит помнить, что React был выпущен за год до Flux, и все же он был принят многими разработчиками независимо.

Конечно, я действительно рассматривал структурирование и реализацию компонентов здесь. Принятие приложения из каркасов в развертывание - гораздо более сложный процесс, и в одном ответе он не может быть подробно рассмотрен. Со временем, вы, вероятно, также хотят, чтобы узнать о:

  • управления пакетами и зависимостями
  • Модуль Упаковщики
  • маршрутизации
  • Hot
  • Перезагрузка
  • ES6/Babel
  • Redux
  • Опорная сторона сервера
  • Неизменяемые данные
  • Встроенные стили
  • Реле/​​Falcor/GraphQL

Это займет некоторое время, чтобы получить этот список вещей, хитрость заключается в том, чтобы не спешить. Естественно, не перенастраивайте свой существующий проект, пока не найдете причины, по которым эти решения существуют.

Думаю react-howto лучший путеводитель там.Несмотря на то, что он не очень подробен, он связан с множеством хороших ресурсов, и, самое главное, он дает упрямое руководство к порядку, в котором вы должны изучить эти технологии на своем пути к тому, чтобы стать компетентным разработчиком ReactJS.

+0

Для этой щедрости - ключ действительно включают базовый пример с потоком –

+2

Если вы можете обосновать, почему вам нужен Flux, я обновлю ответ. –

+0

Потому что его часть потока мне нужно понять, и цель действительно стоит за щедростью - «Используя это jsfiddle, покажите мне, как включить флюс, даже если это фиктивный ответ json». –

0

Выбор рамок (Угловое/React) не мешает строить какой-либо функциональности вы и ваш сайт может быть построен ни с одной, ни с обеих этих фреймворков.

+0

Несомненно, я имею в виду - как перейти от базовых примеров к более тщательно разработанному приложению. Нужно ли создавать инициализатор. Или работайте над созданием div-держателей в разметке, которые затем получают «response-ed» –

+0

Могу ли я иметь такую ​​разметку

, а затем в js-ReactDOM.render (, $ ('* [data-role = "commentbox"] ')); –

0

В то время как вы, конечно, можете объединить Угловое и реагировать, я не уверен, почему вы хотели бы, и это не будет самая легкая задача. Разумеется, это выполнимо, но это будет очень сложно для очень небольшого конечного выигрыша.

Если вы хотите построить SPA с реакцией, я бы больше сосредоточился на поиске реализации Flux, который вам нравится, и изучении того, как его интегрировать. Flux разработан специально для решения проблем с большими SPA-системами, которые могут иметь сложный поток данных, и это, безусловно, инструмент, который легче внедрить на раннем этапе.

Единственная другая библиотека, которую я бы рассматривал вне ворот, будет Immutable.js, которая очень хорошо сочетается как с React, так и с Flux.

В противном случае, пока не найдете , чтобы добавить дополнительные рамки/библиотеки, попытайтесь сдержать. Со всеми захватывающими инфраструктурами JS там очень заманчиво хотеть использовать их все, но на самом деле вам лучше выбрать тот, на котором нужно сосредоточиться, а затем может быть, принося некоторые инструменты из другого позже, когда они необходимы ,

+0

Расскажите подробнее о материалах флюса - например, как бы вы включили или упорядочили код в моем примере выше. Используете ли вы поток для обработки запросов json? –

+0

Да, Flux предназначен для управления данными, как внутри приложения, так и для облегчения взаимодействия с API. Это «недостающая часть» от реакции ваниляра, что очень полезно добавить, если вы собираетесь делать много данных, интенсивных вещей. Существует множество реализаций, наиболее популярными являются [Alt] (http://alt.js.org/) и [Redux] (http://redux.js.org/), или вы можете использовать [ваниль] (https://facebook.github.io/flux/). В любом случае, помимо этих проблем, я думаю, что все остальное, о чем вы говорили, может (и должно) быть обработано в Реактите в одиночку. – gravityplanx

+0

Я вижу - как насчет добавления jquery и подчеркивания? –

Смежные вопросы