7 Sfaturi pentru migrarea de la Backbone la React & Redux

Configurare noua (How To)

Situatie

Solutie

1. Încărcați componentele React

Când utilizați Backbone, organizați interfața aplicației dvs. cu vizualizări. O astfel de vizualizare conține un șablon HTML pe care trebuie să îl redați într-un nod DOM și de obicei trebuie să apelați manual metoda de redare pentru a face acest lucru.

React furnizează componente pentru același scop. Metoda de randare a unei componente returnează șablonul JSX în loc de HTML. Când migrați la React, există două modalități de a face acest lucru.

Mai întâi, puteți integra componentele React în vizualizările Backbone. Aceasta înseamnă că o vizualizare nu va face un șablon HTML sau sub-vizualizări (așa cum se întâmplă de obicei), ci o componentă React ca sub-vizualizare.

De exemplu, să examinăm o implementare standard a metodei de redare într-o vizualizare cu mai multe sub-vizualizări. Aici fiecare sub-vizualizare se transformă într-un nod DOM:

Ar putea fi așa ceva când vom decide să rescrieți antetul cu React:


Apoi, putem înlocui și conținutul și nu vom mai avea nevoie de întreaga vizualizare a paginii Backbone aici (Header, Content și Footer se află acum în componenta paginii):

import React from react;
import ReactDOM from react-dom;
import Page from react/components/page;
ReactDOM.render(<Page />, $(.page)[0]);

Această abordare este foarte utilă dacă aveți o aplicație Backbone mare cu mai multe pagini și propria rutare, deoarece puteți începe să o utilizați oricând și oriunde în interiorul aplicației. Deși în cazul în care aplicația dvs. nu a crescut încă, întâmpinați-vă la următoarea secțiune.

2. Împachetați aplicația cu o componentă React

Dacă aplicația dvs. Backbone este mică și include doar o singură pagină, dar intenționați să o extindeți și pe alte domenii și să utilizați în mod evident rutarea, migrarea la React este probabil chiar mai ușoară în acest caz.

Puteți crea o arhitectură obișnuită de aplicații React utilizând ruterul de reacție pentru a rută între pagini, să scrieți noi pagini ca componente React și să înfășurați singura pagină de backbone pe care o aveți și cu o componentă.

Să presupunem că avem deja pagina de vizualizare a paginilor de bord, dar am decis să scriem noi pagini pentru autentificare cu React. Iata cum arata Routerul nostru:

import React from react;
import ReactDOM from react-dom;
import { Router, Route } from react-router;
import LoginPage from react/components/pages/login;
import SignupPage from react/components/pages/signup;
import DashboardPage from react/components/pages/dashboard;
ReactDOM.render(
<Router history={browserHistory}>
<Route path=/ component={App}>
<Route path=login component={LoginPage} />
<Route path=signup component={SignupPage} />
<Route path=dashboard component={DashboardPage} />
</Route>
</Router>,
document.getElementById(content)
);

Vom face ca paginile de conectare și de înregistrare să fie componente, dar ce se întâmplă cu tabloul de bord? Aici trebuie să creați încă componenta paginii de bord. Cu toate acestea, va face efectiv un gol DOM-nod și apoi vizualizarea Backbone va fi redată în acest nod prin metoda componentDidMount a ciclului de viață.

import React from react;
import DashboardView from views/dashboard;
class DashboardPage extends React.PureComponent {
// render an empty DIV and save a reference to it
render() {
return <div ref={node => this.node = node}></div>;
}
componentDidMount() {
// render a Backbone view into the referenced DIV
this.dashboardView = new DashboardView(this.node, this.props);
this.dashboardView.render();
}
componentWillUnmount() {
// don’t forget to clean up after Backbone
this.dashboardView.remove();
}
}

După ceva timp, poți rescrie tabloul de bord cu React și apoi scapi de Backbone deloc. Puteți, de asemenea, să amestecați această abordare cu prima și să începeți să creați unele componente în interiorul Tabloului de bord dacă este prea greu să rescrieți întreaga vizualizare în acest moment.

3. Adaptați datele existente pentru Redux

Backbone views funcționează cu datele într-un mod Backbone – folosind modele și colecții. De obicei, o vizualizare păstrează exemplele de modele / colecții cu datele necesare în interior. Aceste instanțe pot prelua date de pe server și pot oferi câteva metode utile pentru a lucra cu aceste date.

Alte cuvinte, când încorporați o componentă React, ar putea necesita date deja existente în Backbone. Pentru a nu-l prelua de două ori cu Redux, puteți pune datele din Backbone în Magazinul Redux înainte de montarea componentelor și apoi să lucrați cu ea în modul familiar Redux.

Desigur, dacă doriți să vă conectați React cu Redux folosind reac-redux, trebuie să înfășurați fiecare punct de intrare cu componenta Provider pentru a face această bibliotecă să funcționeze (spre deosebire de o aplicație React obișnuită în care aveți doar un singur furnizor pe partea de sus a ierarhiei).

Există două modalități de a introduce date existente în magazinul Redux. Dacă creați un magazin după preluarea datelor, puteți utiliza starea inițială pentru acesta:

function getInitialState() {
const state = {};
// Let’s suggest that APP is our global Backbone app instanse,
// that keeps some models and collections.
// We put the data from them into initial Redux state.
state.account = APP.models.account.attributes;
state.sellPoints = APP.collections.tasks.map(task => task.attributes);
return state;
}
// A root reducer for the Redux store
function rootReducer(state, action) {
if (!state) {
return getInitialState();
}
// Handle other actions…
}

Un alt mod de a face acest lucru este de a trimite acțiuni care vor pune datele în magazinul deja existent:

import React from react;
import ReactDOM from react-dom;
import { Provider } from react-redux;
import { getStore } from react/store;
import Content from react/components/content;
import Header from views/header;
const Page = Backbone.View.extend({
render() {
const attributes = this.model.attributes;
this.headerView = new Header(this.$(.header), attributes);
this.headerView.render();
// set data to the store through dispathing of the action
getStore().getState().dispatch({
action: SET_TASKS,
data: this.model.attributes.tasks
});
// use Provider to make react-redux work inside of the component
ReactDOM.render(<Provider store={getStore()}>
<Content />
</Provider>,
$(.content)[0]);
return this;
}
});

4. Sincronizați datele între Redux și Backbone

Când puneți datele din Backbone în magazinul Redux, îl veți putea utiliza în componentele React în modul Redux. Dar datele ar putea fi modificate prin acțiunile unui utilizator în vizualizările Backbone. Acesta va fi schimbat într-un model sau într-o colecție, dar rămâne învechit în magazin. Pentru a preveni această problemă, trebuie să sincronizați datele dintre aceste două cadre.

Utilizați dispecerizarea acțiunilor corespunzătoare pentru asta. De exemplu, dacă schimbați titlul într-unul din modelele de activități, expediați acțiunea făcând același lucru în magazin:

import { getStore } from react/store;
const Task = Backbone.View.extend({
events: {
click .saveName: function(e) {
const name = this.nameInput.value;
// Change the name of the task in the model
this.model.set(name, name);
// Then change it in the store
getStore().getState().dispatch({
action: CHANGE_TASK,
data: {
name
}
});
}
}
});

De asemenea, puteți face sincronizarea înapoi pentru un caz în care datele se schimbă în interiorul unei componente React. Aici trebuie să utilizați metoda de abonare a magazinului Redux pentru a asculta când se schimbă:

import { getStore } from react/store;
const Task = Backbone.View.extend({
listenToStore() {
const taskId = this.taskId;
const store = getStore();
// Listen to changes of the Redux store
store.subscribe(() => {
const state = store.getState();
const storeTaskData = state.tasks[taskId];
// Compare if data is changed.
// Because the task reducer in Redux returns a new task object everytime.
if (storeTaskData !== this.model.attributes) {
// Set the changed data to the model
this.model.set(storeTaskData);
// And re-render
this.render();
}
});
}
});

5. Utilizați puterea Webpack pentru a împărți stivele

Când aduceți React pe bord, trebuie să utilizați un încărcător Wepback special pentru a gestiona sintaxa JSX în codul dvs. Dacă doriți un proces de construire mai rapid, ar fi bine să puneți toate componentele într-un director individual (să sugerăm să-l denumiți “reacționați”) și să luați încărcătorul JSX numai pentru el, nu pentru întregul proiect (folosind JSX-loader peste tot va funcționa și pentru că este compatibil cu sintaxa standard JS, dar va funcționa puțin mai încet).

De asemenea, este posibil să doriți să utilizați nu doar CSS în componentele dvs., ci și module CSS mult mai avansate. Și Webpack poate ajuta și în această situație. Tot ce aveți nevoie este config-ul corect – puteți utiliza în continuare CSS-loader pe care l-ați folosit înainte în partea Backbone a proiectului, dar alte opțiuni pentru același încărcător pentru a transforma modulele CSS în elementele React ale acestuia.

Astfel ar putea arăta configurația Webpack:

const config = {
module: {
rules: [
// Use one Babel config for everything but the React part
{
test: /.js$/,
exclude: /react/,
use: [{
loader: ‘babel-loader’,
options: {
presets: [‘es2015’, ‘stage-2’]
}
}]
},
// And use another Babel config for the React part
{
test: /react/.+?.js$/,
use: [{
loader: ‘babel-loader’,
options: {
presets: [‘react’, ‘es2015’, ‘stage-2’]
}
}]
},
// Use one CSS-loader config for everything but the React part
{
test: /.css$/,
exclude: /react/,
use: [
‘style?sourceMap’,
‘css’
]
},
// And use another CSS-loader config (CSS-modules) for the React part
{
test: /react/.+?.css$/,
use: [
‘style?sourceMap’,
‘css?modules&importLoaders=1&localIdentName=[path]___[local]___[hash:base64:5]’
]
},
// Other loaders here…
]
},
// Other settings here…
};

6. Stați departe de stiva anterioară

Încercați să nu utilizați soluțiile arhitecturale din partea Backbone în partea React în creștere, dacă acestea nu se potrivesc acolo. Acestea pot fi aplicabile și este posibil să fiți tentați să le îmbrățișați în loc să vă luați timp pentru implementarea unora mult mai potrivite, dar rețineți că obiectivul dvs. principal este de a rescrie întreaga aplicație mult mai eficient React. Așa că, mai devreme sau mai târziu, veți pleca de la Backbone și dacă părțile sale vor interspersa arhitectura nouă undeva, va fi mult mai greu să scapi de cel vechi.

Deci, încercați să scrieți partea React ca și cum nu știți nimic despre partea din spate.

Următoarea situație ar putea fi un exemplu aici. Ați putea avea o instanță a vederii principale a aplicației în spațiul de nume global. Această instanță ar putea să păstreze câteva modele în interiorul său și să furnizeze anumite metode globale (de exemplu, metode de verificare a rolurilor utilizatorului curent bazate pe modelul acestui utilizator), folosind peste tot în partea din spate a proiectului. Ar putea fi o abordare normală pentru Backbone, dar folosim magazinul Redux pentru astfel de lucruri în grupul React & Redux.

Iată cum ar putea arăta într-o vizualizare Backbone:

import AdminContent from views/adminContent;
import UserContent from views/userContent;
const Page = Backbone.View.extend({
render() {
const contentNode = this.$(.content)[0];
// Use a method of the global app instance
// (the model of the current user is hold there)
if (APP.isAdminUser()) {
this.contentView = new AdminContent(contentNode);
} else {
this.contentView = new UserContent(contentNode);
}
this.contentView.render();
return this;
}
});

Apoi, cum ar putea arăta dacă folosești această modalitate (inadecvată!). În spate într-o componentă React:

import React from react;
import AdminContent from react/components/adminContent;
import UserContent from react/components/userContent;
class Page extends React.PureComponent {
render() {
// a Backbone way – still using the global APP instance
if (APP.isUserAdmin()) {
return <AdminContent />;
} else {
return <UserContent />;
}
export default Page;

Și în final, o soluție corectă pentru calea Redux:

import React from react;
import { connect } from react-redux;
import AdminContent from react/components/adminContent;
import UserContent from react/components/userContent;
class Page extends React.PureComponent {
// Use the state from the store
isUserAdmin() {
return this.props.userRoles.includes(ADMIN);
}
render() {
if (this.isUserAdmin()) {
return <AdminContent />;
} else {
return <UserContent />;
}
}
}
function select(state) {
return {
userRoles: state.userRole
};
}
export default connect(select)(Page);

După cum puteți vedea, este dificil să nu mai utilizați Backbone dacă componentele dvs. React încă mai au părți din ea; și nu necesită nimic dacă creați componente în mod corect.

7. Începeți migrarea la momentul potrivit

Ar putea să nu fie atât de rezonabil să începeți înlocuirea opțiunilor Backbone cu absolut aceleași componente React (adică design și funcționalitate). Aproape fiecare aplicatie web se schimba foarte des in timpul perioadei de viata – vechile caracteristici dau o cale celor noi complet noi sau pur si simplu dobandesc un nou design UI sau UX. Întregii pagini dispar și cele noi vin la locul lor.

În astfel de condiții, ar fi mai înțelept să aplicăm React numai la apariția de noi caracteristici care treptat vor înlocui cele vechi. Veți avea nevoie să faceți aceste noi caracteristici și vă va lua oricum timpul. Deci, este o bună ocazie să petreceți acest timp utilizând noul set, nu cel vechi. Și trebuie să fie chiar mai rapid, eficient și plăcut să facem noi părți cu React (la urma urmei, acesta este motivul pentru care am ales React, nu-i așa?).

Ar fi mai înțelept să aplicăm React numai la apariția de noi caracteristici care treptat le vor înlocui pe cele vechi.
Desigur, dacă aveți mult timp liber să rescrieți o aplicație Backbone așa cum este, ar putea fi o opțiune. Dar este un caz rar și este cu greu posibil în viața reală.

SUCCES!

Tip solutie

Permanent

Voteaza

(13 din 27 persoane apreciaza acest articol)

Despre Autor

Leave A Comment?