React load script on specfic div - javascript

I need to load a script on specific component in my React app.
Below is my script and i need this to load on bottom-most div in my component
<div id="rexxxx"></div>
<script>
new carouselInlineWidget("xx", {
/*Your REVIEWS.io account ID:*/
store: "xxxxxxxxxxxx",
sku: "",
lang: "en",
carousel_type: "xxxxx",
styles_carousel: "CarouselWidget--xxxxxx",
/*Widget settings:*/
options: {
general: {
/*What reviews should the widget display? Available options: company, product, third_party. You can choose one type or multiple separated by comma.*/
enable_auto_scroll: 10000,
},
header: {
},
reviews: {
},
popups: {},
},
styles: {
},
});
</script>
I have my React component
import React from 'react'
import edenredLogo from '../../images/edenred-logo.webp'
import { useHistory } from 'react-router-dom'
import { useSelector } from 'react-redux'
import './landing.less'
const Landing = () => {
const history = useHistory()
return (
<>
<div className="script-here"/>
</>
)
}
export default Landing

You can use the custom hook:
import { useEffect } from 'react';
const useScript = (url, position, async = true) => {
useEffect(() => {
const placement = document.querySelector(position);
const script = document.createElement('script');
script.src = url;
script.async = typeof async === 'undefined' ? true : async;
placement.appendChild(script);
return () => {
placement.removeChild(script);
};
}, [url]);
};
export default useScript;
Usage:
useScript(url, ".script-here");
Or just use dangerouslySetInnerHTML
<div className="script-here" dangerouslySetInnerHTML={{__html: your_script}} />

Related

Mock Service Worker-Expected response resolver to return a mocked response Object but got undefined. The original response is going to be used instead

React Testing Using Mock service worker is returning undefined and then taking values from the actual API. As you can see from the image down below the test is getting passed by getting values from the actual API and the name ARLO WANG is getting pulled out. Where as the name I have kept in the mockResponse is "first last" in the handler.js file.
FollowersList.js
import React, { useEffect, useState } from 'react'
import "./FollowersList.css"
import axios from "axios"
import { Link } from 'react-router-dom';
import { v4 } from 'uuid';
export default function FollowersList() {
const [followers, setFollowers] = useState([]);
useEffect(() => {
fetchFollowers()
}, []);
const fetchFollowers = async () => {
const {data} = await axios.get("https://randomuser.me/api/?results=5")
setFollowers(data.results)
}
// console.log(followers)
return (
<div className="followerslist-container">
<div>
{followers.map((follower, index) => (
<div className="follower-item" key={v4()} data-testid={`follower-item-${index}`}>
<div className="followers-details">
<div className="follower-item-name">
<h4>{follower.name.first}</h4> <h4>{follower.name.last}</h4>
</div>
<p>{follower.login.username}</p>
</div>
</div>
))}
</div>
<div className="todo-footer">
<Link to="/">Go Back</Link>
</div>
</div>
)
}
FollowersList.test.js
import { render, screen } from "#testing-library/react";
import { BrowserRouter } from "react-router-dom";
import FollowersList from "../FollowersList";
const MockFollowersList = () => {
return (
<BrowserRouter>
<FollowersList />
</BrowserRouter>
);
};
describe("FollowersList Component", () => {
test("renders first follower", async () => {
render(<MockFollowersList />);
screen.debug()
expect(await screen.findByTestId("follower-item-0")).toBeInTheDocument();
});
});
src/mock/handler.js
import { rest } from 'msw';
const mockResponse = {
data: {
results: [
{
name: {
first: "first",
last: "last",
},
login: {
username: "x",
},
},
],
},
};
export const handlers = [
rest.get('https://randomuser.me/api/', (req, res, ctx) => {
return res(ctx.json({mockResponse}))
}
})
]
VSCODE terminal
Something is going wrong in the return line in handlers array in the handler file. It's not sending back the mockResponse correctly.
Found the mistake. The response structure returned by the actual API and the msw is different. Just had to remove the 'data' object in the mockResponse and keep the it just as an array of 'results'.
import { rest } from 'msw';
const mockResponse = {
results: [
{
name: {
first: "first",
last: "last",
},
login: {
username: "x",
},
},
],
};
export const handlers = [
rest.get('https://randomuser.me/api/', (req, res, ctx) => {
return res(ctx.json(mockResponse))
}
})
]

Adyencheckout is not a constructor - NextJS

I'm trying to implement the Adyen dropin payment UI using NextJS but I'm having trouble initializing the Adyen dropin component.
I'm need to dynamically import Adyen web or I get the error window is not defined however, after reading through the NextJS docs, dynamic import creates a component which I can't figure out how to use as a constructor.
I tried the code below but receive the error TypeError: AdyenCheckout is not a constructor
I'm new to NextJS and am at a total loss as to how I should import and initialize Adyen.
Can anyone point me in the right direction?
import Head from 'next/head';
import { useRef, useEffect, useState } from 'react';
import {callServer, handleSubmission} from '../util/serverHelpers';
//dynamic import below. Imports as a component
//import dynamic from 'next/dynamic';
//const AdyenCheckout = dynamic(() => import('#adyen/adyen-web'), {ssr: false});
import '#adyen/adyen-web/dist/adyen.css';
export default function Dropin(){
const dropinContainer = useRef(null);
const [paymentMethods, setPaymentMethods] = useState();
//const [dropinHolder, setDropinHolder] = useState();
//Get payment methods after page render
useEffect( async () => {
const response = await callServer(`${process.env.BASE_URL}/api/getPaymentMethods`);
setPaymentMethods(prev => prev = response);
},[]);
//Adyen config object to be passed to AdyenCheckout
const configuration = {
paymentMethodsResponse: paymentMethods,
clientKey: process.env.CLIENT_KEY,
locale: "en_AU",
environment: "test",
paymentMethodsConfiguration: {
card: {
showPayButton: true,
hasHolderName: true,
holderNameRequired: true,
name: "Credit or debit card",
amount: {
value: 2000,
currency: "AUD"
}
}
},
onSubmit: (state, component) => {
if (state.isValid) {
handleSubmission(state, component, "/api/initiatePayment");
}
},
onAdditionalDetails: (state, component) => {
handleSubmission(state, component, "/api/submitAdditionalDetails");
},
};
//const checkout = new AdyenCheckout(configuration);
const AdyenCheckout = import('#adyen/adyen-web').default;
const adyenCheckout = new AdyenCheckout(configuration);
const dropin = adyenCheckout.create('dropin').mount(dropinContainer.current);
return (
<div>
<Head>
<title>Dropin</title>
</Head>
<div ref={dropin}></div>
</div>
)
}
I was able to resolve the issue by importing the module using the default value inside an async function nested in the useEffect function.
import Head from 'next/head';
import { useRef, useEffect, useState } from 'react';
import {callServer, handleSubmission} from '../util/serverHelpers';
import '#adyen/adyen-web/dist/adyen.css';
export default function Dropin(){
const dropinContainer = useRef();
const [paymentMethods, setPaymentMethods] = useState({});
useEffect(() => {
const init = async () => {
const response = await callServer(`${process.env.BASE_URL}/api/getPaymentMethods`)
.then(setPaymentMethods(response));
console.log(paymentMethods);
const configuration = {
paymentMethodsResponse: paymentMethods,
clientKey: process.env.CLIENT_KEY,
locale: "en_AU",
environment: "test",
paymentMethodsConfiguration: {
card: {
showPayButton: true,
hasHolderName: true,
holderNameRequired: true,
name: "Credit or debit card",
amount: {
value: 2000,
currency: "AUD"
}
}
},
onSubmit: (state, component) => {
if (state.isValid) {
handleSubmission(state, component, "/api/initiatePayment");
}
},
onAdditionalDetails: (state, component) => {
handleSubmission(state, component, "/api/submitAdditionalDetails");
},
};
console.log(configuration.paymentMethodsResponse);
const AdyenCheckout = (await import('#adyen/adyen-web')).default;
const checkout = new AdyenCheckout(configuration);
checkout.create('dropin').mount(dropinContainer.current);
}
init();
},[]);
return (
<div>
<Head>
<title>Dropin</title>
</Head>
<div ref={dropinContainer}></div>
</div>
)
}

React Hooks/Context & Elastictic UI. Problem with fetched data (REST) in function Component

I'm quite new to React Hooks/Context so I'd appreciate some help. Please don' t jump on me with your sharp teeth. I Checked other solutions and some ways i've done this before but can't seem to get it here with the 'pick from the list' way.
SUMMARY
I need to get the municipios list of names inside of my const 'allMunicipios'(array of objects) inside of my Search.js and then display a card with some data from the chosen municipio.
TASK
Get the data from eltiempo-net REST API.
Use Combobox async element from Elastic UI to choose from list of municipios.
Display Card (from elastic UI too) with some info of chosen municipio.
It has to be done with function components / hooks. No classes.
I'd please appreciate any help.
WHAT I'VE DONE
I've created my reducer, context and types files in a context folder to fecth all data with those and then access data from the component.
I've created my Search.js file. Then imported Search.js in App.js.
I've accesed the REST API and now have it in my Search.js
PROBLEM
Somehow I'm not beeing able to iterate through the data i got.
Basically i need to push the municipios.NOMBRE from api to the array const allMunicipios in my search.js component. But when i console log it it gives me undefined. Can;t figure out why.
I'll share down here the relevant code/components. Thanks a lot for whoever takes the time.
municipiosReducer.js
import {
SEARCH_MUNICIPIOS,
CLEAR_MUNICIPIOS,
GET_MUNICIPIO,
GET_WEATHER,
} from "./types";
export default (state, action) => {
switch (action.type) {
case SEARCH_MUNICIPIOS:
return {
...state,
municipios: action.payload,
};
case GET_MUNICIPIO:
return {
...state,
municipio: action.payload,
};
case CLEAR_MUNICIPIOS:
return {
...state,
municipios: [],
};
case GET_WEATHER: {
return {
...state,
weather: action.payload,
};
}
default:
return state;
}
};
municipiosContext.js
import { createContext } from "react";
const municipiosContext = createContext();
export default municipiosContext;
MunicipiosState.js
import React, { createContext, useReducer, Component } from "react";
import axios from "axios";
import MunicipiosContext from "./municipiosContext";
import MunicipiosReducer from "./municipiosReducer";
import {
SEARCH_MUNICIPIOS,
CLEAR_MUNICIPIOS,
GET_MUNICIPIO,
GET_WEATHER,
} from "./types";
const MunicipiosState = (props) => {
const initialState = {
municipios: [],
municipio: {},
};
const [state, dispatch] = useReducer(MunicipiosReducer, initialState);
//Search municipios
//In arrow functions 'async' goes before the parameter.
const searchMunicipios = async () => {
const res = await axios.get(
`https://www.el-tiempo.net/api/json/v2/provincias/08/municipios`
// 08 means barcelona province. This should give me the list of all its municipios
);
dispatch({
type: SEARCH_MUNICIPIOS,
payload: res.data.municipios,
});
};
//Get Municipio
const getMunicipio = async (municipio) => {
const res = await axios.get(
`https://www.el-tiempo.net/api/json/v2/provincias/08/municipios/${municipio.CODIGOINE}`
//CODIGOINE is in this REST API kind of the ID for each municipio.
//I intent to use this later to get the weather conditions from each municipio.
);
dispatch({ type: GET_MUNICIPIO, payload: res.municipio });
};
const dataMunicipiosArray = [searchMunicipios];
//Clear Municipios
const clearMunicipios = () => {
dispatch({ type: CLEAR_MUNICIPIOS });
};
return (
<MunicipiosContext.Provider
value={{
municipios: state.municipios,
municipio: state.municipio,
searchMunicipios,
getMunicipio,
clearMunicipios,
dataMunicipiosArray,
}}
>
{props.children}
</MunicipiosContext.Provider>
);
};
export default MunicipiosState;
Search.js
import "#elastic/eui/dist/eui_theme_light.css";
import "#babel/polyfill";
import MunicipiosContext from "../contexts/municipiosContext";
import MunicipiosState from "../contexts/MunicipiosState";
import { EuiComboBox, EuiText } from "#elastic/eui";
import React, { useState, useEffect, useCallback, useContext } from "react";
const Search = () => {
const municipiosContext = useContext(MunicipiosContext);
const { searchMunicipios, municipios } = MunicipiosState;
useEffect(() => {
return municipiosContext.searchMunicipios();
}, []);
const municipiosFromContext = municipiosContext.municipios;
const bringOneMunicipio = municipiosContext.municipios[0];
let municipiosNames = municipiosFromContext.map((municipio) => {
return { label: `${municipio.NOMBRE}` };
});
console.log(`municipiosFromContext`, municipiosFromContext);
console.log(`const bringOneMunicipio:`, bringOneMunicipio);
console.log(`municipiosNames:`, municipiosNames);
const allMunicipios = [
{ label: "santcugat" },
{ label: "BARCELONETA" },
{ label: "BARCE" },
];
const [selectedOptions, setSelected] = useState([]);
const [isLoading, setLoading] = useState(false);
const [options, setOptions] = useState([]);
let searchTimeout;
const onChange = (selectedOptions) => {
setSelected(selectedOptions);
};
// combo-box
const onSearchChange = useCallback((searchValue) => {
setLoading(true);
setOptions([]);
clearTimeout(searchTimeout);
// eslint-disable-next-line react-hooks/exhaustive-deps
searchTimeout = setTimeout(() => {
// Simulate a remotely-executed search.
setLoading(false);
setOptions(
municipiosNames.filter((option) =>
option.label.toLowerCase().includes(searchValue.toLowerCase())
)
);
}, 1200);
}, []);
useEffect(() => {
// Simulate initial load.
onSearchChange("");
}, [onSearchChange]);
return (
<div>
<EuiComboBox
placeholder="Search asynchronously"
async
options={options}
selectedOptions={selectedOptions}
isLoading={isLoading}
onChange={onChange}
onSearchChange={onSearchChange}
/>
<button>Lista de municipios</button>
</div>
);
};
export default Search;
also the
Home.js
import React, { useState } from "react";
import { EuiComboBox, EuiText } from "#elastic/eui";
// import { DisplayToggles } from "../form_controls/display_toggles";
import "#babel/polyfill";
import "#elastic/eui/dist/eui_theme_light.css";
import Search from "./Search";
import MunicipioCard from "./MunicipioCard";
const Home = () => {
return (
<div>
<EuiText grow={false}>
<h1>Clima en la provincia de Barcelona</h1>
<h2>Por favor seleccione un municipio</h2>
</EuiText>
<Search />
<MunicipioCard />
</div>
);
};
export default Home;
App.js
import "#babel/polyfill";
import "#elastic/eui/dist/eui_theme_light.css";
import { EuiText } from "#elastic/eui";
import React from "react";
import Home from "./components/Home";
import MunicipiosState from "./contexts/MunicipiosState";
import "./App.css";
function App() {
return (
<MunicipiosState>
<div className="App">
<EuiText>
<h1>App Component h1</h1>
</EuiText>
<Home />
</div>
</MunicipiosState>
);
}
export default App;
You are using forEach and assigning the returned value to a variable, however forEach doesn't return anything. You should instead use map
let municipiosNames = municipiosFromContext.map((municipio) => {
return `label: ${municipio.NOMBRE}`;
});
As per your comment:
you data is loaded asynchronously, so it won't be available on first render and since functional components depend on closures, you onSearchChange function takes the value from the closure at the time of creation and even if you have a setTimeout within it the updated value won't reflect
The solution here is to add municipiosFromContext as a dependency to useEffect
const onSearchChange = useCallback((searchValue) => {
setLoading(true);
setOptions([]);
clearTimeout(searchTimeout);
// eslint-disable-next-line react-hooks/exhaustive-deps
searchTimeout = setTimeout(() => {
// Simulate a remotely-executed search.
setLoading(false);
setOptions(
municipiosNames.filter((option) =>
option.label.toLowerCase().includes(searchValue.toLowerCase())
)
);
}, 1200);
}, [municipiosFromContext]);
useEffect(() => {
// Simulate initial load.
onSearchChange("");
}, [onSearchChange]);

Link outside a Router Error, while everything set up properly

Ok, I have no idea why this is not working. Everything is set up properly from what I can see.
I am using "react-router-dom": "^5.0.0"
The code also uses the Tabulator grid library, specifically the React implementation of it. It's not really relevant, just wanted to note it.
The code works 100% without using the sub-component links, so the problem is not there.
The grid generator in Journals creates a table, which has link cells, which lead to the Journal component.
The link component is generated fine, it just doesn't work for reasons I don't know.
CodeSandbox
If you comment out the formatter line in columns in the Journal component, the app works again.
App.js
import React, { Component } from 'react';
import { BrowserRouter as Router, Route } from 'react-router-dom';
import Header from './components/layout/Header';
import Dashboard from './components/pages/Dashboard';
import Journals from './components/pages/Journals';
import Journal from './components/pages/Journal';
class App extends Component {
render() {
return (
<Router>
<div className="App">
<div className="container">
<Header />
<div className="content">
<Route exact path="/" component={Dashboard} />
<Route exact path="/journals" component={Journals} />
<Route path="/journals/:key" component={Journal} /> // <------ ROUTE IS HERE
</div>
</div>
</div>
</Router>
);
}
}
export default App;
Journals.js
import React, { useState, useEffect } from "react";
import { Link } from 'react-router-dom';
import { ReactTabulator } from 'react-tabulator'
import "tabulator-tables/dist/css/tabulator.min.css";
import { reactFormatter } from 'react-tabulator';
function Journals() {
const [journals, setJournals] = useState([]);
useEffect(() => {
fetch("http://localhost:4000/journals")
.then(res => res.json())
.then(data => {
setJournals(data)
})
.catch(err => err);
}, []);
const JournalLink = (props) => {
const cellData = props.cell._cell.row.data;
let key = cellData.key_
let link = `/journals/${key}`
return <Link to={link}>{key}</Link>; // <------ LINK COMPONENT IS HERE
}
const columns = [
{
title: "Number",
field: "key_",
formatter: reactFormatter(<JournalLink />) // <------ LINK COMPONENT USED HERE
},
{ title: "Date", field: "date_" },
];
return (
<div>
<h1>Journals</h1>
<ReactTabulator
data={journals}
columns={columns}
tooltips={true}
layout={"fitData"}
/>
</div >
)
}
export default Journals;
reactFormatter usage example
reactFormatter definition
Journal.js
import React, { useState, useEffect } from "react";
import { ReactTabulator } from 'react-tabulator'
import "tabulator-tables/dist/css/tabulator.min.css";
function Journal(props) {
const [journalItems, setJournalItems] = useState([]);
const initialFormJournalItems = {
id: "",
journalId: "",
companyId: "",
documentKey: "",
documentDate: "",
debitAccount: "",
debit: "",
creditAccount: "",
credit: ""
}
const [formJournalItems, setFormJournalItems] = useState(initialFormJournalItems);
useEffect(() => {
fetch(`http://localhost:4000/journals/${props.match.params.key}`)
.then(res => res.json())
.then(data => {
setJournalItems(data)
})
.catch(err => err);
}, []);
const columns = [
{ title: "Document", field: "documentKey" },
{ title: "Date", field: "documentDate" },
];
return (
<div>
<h1>Journal</h1>
<ReactTabulator
data={journalItems}
columns={columns}
tooltips={true}
layout={"fitData"}
/>
</div >
)
}
export default Journal;
react-tabulator reFormatter is incompatible with react-router library.
https://github.com/ngduc/react-tabulator/blob/0.10.3/lib/Utils.js#L30
From source code,
function reactFormatter(JSX) {
return function customFormatter(cell, formatterParams, onRendered) {
//cell - the cell component
//formatterParams - parameters set for the column
//onRendered - function to call when the formatter has been rendered
onRendered(function () {
var cellEl = cell.getElement();
var CompWithMoreProps = React.cloneElement(JSX, { cell: cell });
react_dom_1.render(CompWithMoreProps, cellEl.querySelector('.formatterCell'));
});
return '<div class="formatterCell"></div>';
};
}
rendering of a formatted element uses the ReactDOM.render function to render the formatted element directly to DOM isolated from parent elements.
A fix to react-tabulator needs to be done to support this use case. One way to go is to have customFormatter return a custom component that provides a way to set its state from outside it. Then onRendered can call this function to set cell.

General State Questions with ReactJS & Reflux

I'm pretty new to React and am trying to wrap my mind around Reflux.
Here's my scenario:
I currently have a very simple app that is calling some song data from a rest api, once retrieved, it is being stored in state.songs (this is happening within an Init function in the song store):
var SongStore = Reflux.createStore({
listenables: [SongActions],
getInitialState: function() {
return []
},
init: function() {
request('http://127.0.0.1:1337/api/songs', function(error, response, body) {
if (!error && response.statusCode == 200) {
var content = JSON.parse(body);
this.trigger(content);
}
}.bind(this));
},
onHandleClick: function(album_link) {
// this.state.songs is undefined here??
}
});
Here's the component that's rendering the song data:
var Home = React.createClass({
mixins: [Reflux.connect(SongStore, 'songs')],
render: function() {
return (
<div className={'react-app-home'}>
<div className="float-left">
<div className="song-data">
{this.state.songs.map(function(song) {
return <div><p>{song.lyrics}</p></div>
})}
</div>
</div>
<div className="float-right">
<AlbumList />
</div>
</div>
);
}
});
This is all working as intended.
I also have a list of albums, which is rendered in it's own component (and has it's own store), and i'm trying to hook up a click function on an album item, so once an album title is clicked, this.state.songs is filtered and the songs component is re-rendered.
The issue i'm having is when I try to access this.state.songs from the song store, it's undefined (see onHandleClick func in song store above).
Album list component:
var AlbumList = React.createClass({
mixins: [Reflux.connect(AlbumStore, 'albums'),
Reflux.connect(SongStore, 'songs')],
render: function() {
return (
<div className="album-list">
{this.state.albums.map(function(album) {
return <p onClick={SongStore.onHandleClick.bind(null, album.album_link)}>{album.album_name}</p>
})}
</div>
);
}
});
Album list store:
var AlbumStore = Reflux.createStore({
listenables: [AlbumActions],
getInitialState: function() {
return [];
},
onReload: function() {
request('http://0.0.0.0:1337/api/albums', function(error, response, body) {
if (!error && response.statusCode == 200) {
var content = JSON.parse(body);
this.trigger(content);
}
}.bind(this));
},
init: function() {
this.onReload();
}
});
Can anyone help me out? An answer with some explaining would be awesome so I can understand what the problem is.
Thanks!
You should be using actions for handleClick or any other call from the component to the store. I would also suggest separating your api calls from the store. Here is an example from https://github.com/calitek/ReactPatterns React.14/ReFluxSuperAgent.
app.js
'use strict';
import React from 'react';
import ReactDom from 'react-dom';
import AppCtrl from './components/app.ctrl.js';
import Actions from './actions/api.Actions';
import ApiStore from './stores/Api.Store';
window.ReactDom = ReactDom;
Actions.apiInit();
ReactDom.render( <AppCtrl />, document.getElementById('react') );
Note the action and api.store import.
Here is api.store.
import Reflux from 'reflux';
import Actions from '../actions/api.Actions';
import ApiFct from '../utils/sa.api';
let ApiStoreObject = {
newData: {
"React version": "0.14",
"Project": "ReFluxSuperAgent",
"currentDateTime": new Date().toLocaleString()
},
listenables: Actions,
apiInit() { ApiFct.setData(this.newData); },
apiInitDone() { ApiFct.getData(); },
apiSetData(data) { ApiFct.setData(data); }
}
const ApiStore = Reflux.createStore(ApiStoreObject);
export default ApiStore;
apiInit is doing a setData here but it could be the initial get calls.
Here it the api.
import request from 'superagent';
import apiActions from '../actions/api.Actions';
import saActions from '../actions/sa.Actions';
module.exports = {
getData() { request.get('/routes/getData').end((err, res) => { this.gotData(res.body); }); },
gotData(data) { saActions.gotData1(data); saActions.gotData2(data); saActions.gotData3(data); },
setData(data) { request.post('/routes/setData').send(data).end((err, res) => { apiActions.apiInitDone(); }) },
};
Here we use actions to pass the data to the store.
Here is the store.
import Reflux from 'reflux';
import Actions from '../actions/sa.Actions';
import AddonStore from './Addon.Store';
import MixinStoreObject from './Mixin.Store';
function _GotData(data) { this.data1 = data; BasicStore.trigger('data1'); }
let BasicStoreObject = {
init() { this.listenTo(AddonStore, this.onAddonTrigger); },
data1: {},
listenables: Actions,
mixins: [MixinStoreObject],
onGotData1: _GotData,
onAddonTrigger() { BasicStore.trigger('data2'); },
getData1() { return this.data1; },
getData2() { return AddonStore.data2; },
getData3() { return this.data3; }
}
const BasicStore = Reflux.createStore(BasicStoreObject);
export default BasicStore;
Note that reflux allows you to pass parameters in trigger.
Here is the component.
import React from 'react';
import BasicStore from '../stores/Basic.Store';
let AppCtrlSty = {
height: '100%',
padding: '0 10px 0 0'
}
const getState = () => {
return {
Data1: BasicStore.getData1(),
Data2: BasicStore.getData2(),
Data3: BasicStore.getData3()
};
};
class AppCtrlRender extends React.Component {
render() {
let data1 = JSON.stringify(this.state.Data1, null, 2);
let data2 = JSON.stringify(this.state.Data2, null, 2);
let data3 = JSON.stringify(this.state.Data3, null, 2);
return (
<div id='AppCtrlSty' style={AppCtrlSty}>
React 0.14 ReFlux with SuperAgent<br/><br/>
Data1: {data1}<br/><br/>
Data2: {data2}<br/><br/>
Data3: {data3}<br/><br/>
</div>
);
}
}
export default class AppCtrl extends AppCtrlRender {
constructor() {
super();
this.state = getState();
}
componentDidMount = () => { this.unsubscribe = BasicStore.listen(this.storeDidChange); }
componentWillUnmount = () => { this.unsubscribe(); }
storeDidChange = (id) => {
switch (id) {
case 'data1': this.setState({Data1: BasicStore.getData1()}); break;
case 'data2': this.setState({Data2: BasicStore.getData2()}); break;
case 'data3': this.setState({Data3: BasicStore.getData3()}); break;
default: this.setState(getState());
}
}
}
We are not using mixins. React classes are deprecating mixins so now is a good time to do without. It may seen like overkill to use an extra store and api util but good practices are always good practice.
Map allows passing this with an optional parameter map(function(item){}, this);

Categories