Below is the code of the Service
import { fetchEventSource } from '#microsoft/fetch-event-source';
export const AlertFetchEventSource = () => {
fetchEventSource('https://puppygifs.tumblr.com/api/read/json'),
{
onmessage(ev) {
const data = JSON.parse(ev.data);
return data;
},
};
};
export default { AlertFetchEventSource };
index.tsx where I am making the call to this service but its not returning any data
import React, { Component } from 'react';
import { render } from 'react-dom';
import Hello from './Hello';
import './style.css';
import backendService from './services/backendService';
interface AppProps {}
interface AppState {
name: string;
}
class App extends Component<AppProps, AppState> {
constructor(props) {
super(props);
this.state = {
name: 'React',
};
console.log(backendService.AlertFetchEventSource());
}
render() {
return (
<div>
<Hello name={this.state.name} />
<p>Start editing to see some magic happen :)</p>
</div>
);
}
}
render(<App />, document.getElementById('root'));
Given the library you're using is an event handler, it doesn't ever actually return data. You'd need to provide it a callback to execute when it receives events.
// you might want to specify a better type than `any`
type MessageHandler = (data: any) => void;
export const AlertFetchEventSource = (onEvent: MessageHandler) => {
fetchEventSource('https://puppygifs.tumblr.com/api/read/json'), {
onmessage(ev) {
const data = JSON.parse(ev.data);
onEvent(data);
},
}); // you had a typo here, missing ")"
};
and use it like
import { AlertFetchEventSource } from "./services/backendService";
// snip
AlertFetchEventSource(data => {
// handle event data, eg
console.log(data);
// or perhaps something like
this.setState(data);
});
Related
enter image description here
When I tried to destructure the notification_menu value am getting the error
like this
am using Redux for state management
enter image description here
import React, { Suspense,Component } from 'react';
import { Switch, Route } from "react-router-dom";
import { connect } from 'react-redux';
import { NotificationMenu } from "./Redux/NotificationMenu/nof_selector";
class App extends Component {
state = {
navOpen: false,
};
NavCall = () => {
this.setState({ navOpen: !this.state.navOpen });
};
render() {
console.log(this.props.notification_menu);
const { navOpen } = this.state;
const NavOpenStyleMargin = navOpen ? { marginLeft: "250px" } : {};
return (
<div>
</div>
)
}
}
const mapStateToProps = (state:any) => {
return {
// userID: selectCurrentUser(state),
// account_menu: AccountMenu(state),
notification_menu: NotificationMenu(state),
};
};
export default connect(mapStateToProps,null)(App);
when using typescript you need to declare props and state types to your class component like:
interface IProps {
notification_menu: string // define what type notification_menu is
}
interface IState {
navOpen: boolean
}
class MyComponent extends React.Component<IProps, IState> {
// code here
}
I'm trying to update my home componentstate by getting data from the redux store every time the store is updated. I'm not sure what's wrong with the code below. I can't listen to store changes in my `home component.
my dispatch function is handled in this class.
export class GanttFilter extends Component {
...
handleSubmit = () => {
this.gFilter.filterGanttData(this.formValues)
.then((result) => {
if (result.data)
this.props.dispatch(ganttActions.loadGanttData(result.data));
});
}
...
GanttFilter.propTypes = {
dispatch: PropTypes.func.IsRequired
};
function mapStateToProps(state) {
return {
ganttData: state.gantt.ganttData
};
}
export default connect(mapStateToProps)(GanttFilter);
What I would like to do every time dispatch is called and the data changes, is update the state in my home component. Here is the component.
export class Home extends Component {
constructor() {
super();
this.state = {
data: [],
links: []
};
}
render() {
return (
<div className="fill">
<Gantt data={this.state.data} links={this.state.links} />
</div>
);
}
}
Home.propTypes = {
data: PropTypes.IsRequired
};
function mapStateToProps(state) {
return {
data: state.gantt.ganttData
};
}
export default connect(mapStateToProps)(Home);
the function mapStateToProps is never hit when I set a break point. How can I listen to changes to the store from the home component and update state?
Edit: Here is the wrapper component
function renderApp() {
// This code starts up the React app when it runs in a browser. It sets up the routing
// configuration and injects the app into a DOM element.
const baseUrl = document.getElementsByTagName("base")[0].getAttribute("href");
ReactDOM.render(
<ReduxProvider store={store}>
<AppContainer>
<BrowserRouter children={routes} basename={baseUrl} />
</AppContainer>
</ReduxProvider>,
document.getElementById("react-app")
);
}
reducers
const actionTypes = require('../actions/actionTypes');
const gantt = {
ganttData: [],
selectedTask: null
};
export default function ganttReducer(state = gantt, action) {
switch (action.type) {
case actionTypes.loadGanttData:
return { ...state, ganttData: [...action.ganttData] };
default:
return state;
}
}
root reducer
import { combineReducers } from 'redux';
import gantt from './ganttReducer';
const rootReducer = combineReducers({
gantt
});
export default rootReducer;
actions
const actionTypes = require('./actionTypes');
export function loadGanttData(ganttData) {
return { type: actionTypes.loadGanttData, ganttData };
}
export function getSelectedTask(ganttTask) {
return { type: actionTypes.setSelectedTask, ganttTask };
}
Error:
Make sure you import your Home component using import Home from '...' as opposed to import { Home } from '...', otherwise you'd be grabbing the unconnected component. In general, I would also avoid exporting the unconnected component.
Change this:
render() {
return (
<div className="fill">
<Gantt data={this.state.data} links={this.state.links} />
</div>
);
}
To
render() {
return (
<div className="fill">
<Gantt data={this.props.data} links={this.state.links} />
</div>
);
}
Your data is comming from your props (redux), not from your state.
I'm making a markdown editor using Marked library like this <div id="preview" dangerouslySetInnerHTML={ {__html: marked('Rendered by **marked**.''></div> but get TypeError: Object(...) is not a function.
Found two relevant posts on SO; first and second I'm using the same syntax as the answers but I get a TypeError. In both posts they used ReactDOM.render() method in the end. Full code:
import React, { Component } from 'react';
import './App.css';
import { Provider, connect } from 'react-redux';
import { createStore } from'redux';
import { marked } from "marked";
// Redux
const ADD = "ADD";
const addText = (text) => {
return {
type: ADD,
text: text
}
};
const textReducer = (state = {text: ''}, action) => {
switch(action.type) {
case ADD:
return Object.assign({},state, { text: action.text })
default:
return state
}
};
const store = createStore(textReducer);
// React
class App extends Component {
constructor(props){
super(props)
/*this.state = {
input : ''
}*/
this.handleChange = this.handleChange.bind(this);
};
handleChange(e){
/*this.setState({
input: e.target.value
})*/
this.props.addText(e.target.value)
};
render(){
return(
<div className="App-header">
<textarea id="editor" value={this.props.text} onChange={this.handleChange}></textarea>
<div id="preview" dangerouslySetInnerHTML={ {__html: marked('Rendered by **marked**.') } }></div>
</div>
)
}
};
// React-Redux
const mapStateToProps = (state) => {
return {
text: state.text
}
};
const mapDispatchToProps = (dispatch) => {
return {
addText: (text) => {
dispatch(addText(text))
}
}
};
const Container = connect(mapStateToProps, mapDispatchToProps)(App);
// eslint-disable-next-line
export default class AppWrapper extends Component {
render() {
return(
<Provider store={store}>
<Container />
</Provider>
);
}
};
The markdown text suppose to be rendered as html in preview element but instead I get TypeError: Object(...) is not a function.
UPDATE: apparently redux was not setup properly and was set to an array instead of object. I fixed that but I still get the same error.
I found the solution, problem was I imported marked as named import {import {marked} from 'marked' instead of import as default like this import marked from 'marked'
I have the following code where inside my React component I'm using a third party component -- FineUploader in my case.
Upon uploading files, it calls its onComplete function. From here, I'm trying to call my action creators to handle post-upload processes but I'm unable to access my props or actions from there because this is all outside of my component.
Up to that point, everything is working. I'm able to call uploader instance from my component and upload the file to my Azure Blob Storage and get the fileName and blobName once the upload is completed.
It's funny that I'm stuck at the easier part!
Here's my component:
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import FineUploaderAzure from 'fine-uploader-wrappers/azure'
// Components
import Gallery from './gallery/index';
// Actions
import * as myActions from '../myActions';
// Instantiate FineUploader
const uploader = new FineUploaderAzure({
options: {
cors: {
expected: true,
sendCredentials: false
},
signature: {
endpoint: 'http://localhost:123/getsas'
},
request: {
endpoint: 'https://myaccount.blob.core.windows.net/my-container'
},
callbacks: {
onComplete: function (id, name, responseJSON, xhr) {
const fileName = uploader.methods.getName(id);
const blobName = uploader.methods.getBlobName(id);
// I now need to call my action creator to handle backend stuff
// Or I can call the handleFileUpload function inside my component.
// How do I access either my action creator or handleFileUpload function from here?
}
}
}
})
class FileUploader extends Component {
constructor(props) {
super(props);
this.handleFileUpload = this.handleFileUpload.bind(this);
}
handleFileUpload(fileName, blobName) {
debugger;
}
render() {
return (
<Gallery uploader={uploader} />
)
}
}
function mapStateToProps(state, ownProps) {
return {
}
}
function mapDispatchToProps(dispatch, ownProps) {
return {
actions: bindActionCreators(myActions, dispatch)
};
}
export default connect(mapStateToProps, mapDispatchToProps)(FileUploader)
I came up with the following approach that works. I'm not sure if this is the best way or there's a more elegant approach. I won't accept my answer as the correct one and let everyone post their comments and votes.
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import FineUploaderAzure from 'fine-uploader-wrappers/azure'
// Components
import Gallery from './gallery/index';
// Actions
import * as myActions from '../myActions';
// Instantiate FineUploader
const uploader = new FineUploaderAzure({
options: {
cors: {
expected: true,
sendCredentials: false
},
signature: {
endpoint: 'http://localhost:123/getsas'
},
request: {
endpoint: 'https://myaccount.blob.core.windows.net/my-container'
}
}
})
class FileUploader extends Component {
constructor(props) {
super(props);
this.handleFileUpload = this.handleFileUpload.bind(this);
}
componentDidMount() {
uploader.on('complete', (id, name, responseJSON, xhr) => {
const originalName = uploader.methods.getName(id);
const blobName = uploader.methods.getBlobName(id);
this.handleFileUpload(originalName, blobName);
}
}
handleFileUpload(fileName, blobName) {
// Received fileName and blobName. We can call our actions creators here.
this.props.actions.someAction(fileName, blobName);
}
render() {
return (
<Gallery uploader={uploader} />
)
}
}
function mapStateToProps(state, ownProps) {
return {
}
}
function mapDispatchToProps(dispatch, ownProps) {
return {
actions: bindActionCreators(myActions, dispatch)
};
}
export default connect(mapStateToProps, mapDispatchToProps)(FileUploader)
I have just taken over a new reactjs project -- and I am trying to review how language switching has been invoked.
so like there are two links in the footer to do this language switch.
//footer.js
import React from 'react'
import { Link } from 'react-router-dom'
import { connect } from 'react-redux'
import { bindActionCreators } from 'redux'
import { selectLanguage, getLangDetails } from '../../actions/action_language'
import langObject from './Footer.lang'
class Footer extends React.Component {
constructor (props) {
super(props)
this.changeLanguageToGerman = this.changeLanguageToGerman.bind(this)
this.changeLanguageToEnglish = this.changeLanguageToEnglish.bind(this)
}
changeLanguageToGerman () {
this.props.selectLanguage('de')
}
changeLanguageToEnglish () {
this.props.selectLanguage('en')
}
render () {
let activeLang = 'language--active'
let alternativeLang = 'language--hover'
const lang = getLangDetails(this.props.active_language, langObject)
return (
<div>
<footer className='main-footer show-for-medium-only'>
<div className='medium-15 columns'>
<p className='text--white grid__row--offset--15 footer-text'>
<Link to={this.props.deURL} className={`text--white footer-text ${this.props.active_language === 'de' ? activeLang : alternativeLang}`} onClick={this.changeLanguageToGerman}>DE</Link>
|
<Link to={this.props.enURL} className={`text--white footer-text ${this.props.active_language === 'en' ? activeLang : alternativeLang}`} onClick={this.changeLanguageToEnglish}>EN</Link>
</p>
</div>
</footer>
</div>
)
}
}
const mapStateToProps = (state) => {
return {
active_language: state.active_language
}
}
function mapDispatchToProps (dispatch) {
return bindActionCreators({selectLanguage: selectLanguage}, dispatch)
}
const { string, func } = React.PropTypes
Footer.propTypes = {
deURL: string,
enURL: string,
selectLanguage: func,
active_language: string
}
export default connect(mapStateToProps, mapDispatchToProps)(Footer)
// header.js
import React from 'react'
import { connect } from 'react-redux'
import { getLangDetails } from '../../actions/action_language'
import langObject from './Header.lang'
class Header extends React.Component {
render () {
let transparent
transparent = this.props.transparent ? 'transparent' : ''
const lang = getLangDetails(this.props.active_language, langObject)
return (
<div>
<header className={` main_headerbar__landing transition show-for-large-up ${transparent} `}>
<div className='contain-to-grid'>
{lang}
</div>
</header>
</div>
)
}
}
const mapStateToProps = (state) => {
return {
active_language: state.active_language
}
}
const { bool, string } = React.PropTypes
Header.propTypes = {
transparent: bool,
active_language: string
}
export default connect(mapStateToProps)(Header)
--- so these are the header/footer components - and each has a json file that splits into an array of lang.
there is a file that looks like some global js that I think hooks into this - but I am struggling to extend this functionality into the rest of the site components/pages
//action_language.js
export const LANGUAGE_SELECTED = 'LANGUAGE_SELECTED'
export function selectLanguage (language) {
return {
type: LANGUAGE_SELECTED,
payload: language
}
}
export function getLangDetails (language = 'de', langObject) {
const langData = langObject.langs.filter((langVar) => langVar.lang === language)
return langData['0'].lines
}
ok - so here is the first page -- called services. Now what throws me first here is rather than use active_language its now just language.
//services.js
import React from 'react'
import Header from '../HeaderLanding/Header'
import Footer from '../Footer/Footer'
import NoBundle from './NoBundle'
import HowTiles from './HowTiles'
import CarouselTiles from './CarouselTiles'
import YourAdvantages from './YourAdvantages'
import InformationTiles from './InformationTiles'
import ContactTiles from './ContactTiles'
import { connect } from 'react-redux'
import { bindActionCreators } from 'redux'
import { selectLanguage, getLangDetails } from '../../actions/action_language'
// language file
import langObject from './services.lang.json'
// services css
import './services.css'
// getting the distinct URLs from the lang files
const deURL = langObject.langs[0].pageURL
const enURL = langObject.langs[1].pageURL
const Spacers = () => (
<div>
<div className='row show-for-large-up' style={{ height: '250px' }} />
<div className='row show-for-medium-only' style={{ height: '150px' }} />
<div className='row show-for-small-only' style={{ height: '80px' }} />
</div>
)
class Services extends React.Component {
constructor (props) {
super(props)
this.language = props.match.params.langURL
}
componentWillMount () {
document.getElementById('body').className = 'overlay-background-services'
this.updateLanguage()
}
updateLanguage () {
console.log('updatelang', this.language)
if (this.language === 'de' || !this.language) {
this.props.selectLanguage('de')
} else {
this.props.selectLanguage('en')
}
}
componentWillUnmount () {
document.getElementById('body').className = ''
}
render () {
const lang = getLangDetails(this.language, langObject)
return (
<div>
<Header transparent />
<Spacers />
<NoBundle lang={lang} />
<HowTiles />
<CarouselTiles />
<YourAdvantages />
<InformationTiles />
<ContactTiles />
<Footer deURL={deURL} enURL={enURL} />
</div>
)
}
}
const mapStateToProps = (state) => {
return {
language: state.language
}
}
function mapDispatchToProps (dispatch) {
return bindActionCreators({selectLanguage: selectLanguage}, dispatch)
}
const { func, string, object } = React.PropTypes
Services.propTypes = {
selectLanguage: func,
langURL: string,
params: object,
match: object
}
export default connect(mapStateToProps, mapDispatchToProps)(Services)
The Footer component deals with setting the current language by invoking the Redux action creator selectLanguage. Essentially this dispatches an action (you can think of this as a custom event with some corresponding data - the language) to the store that will persist the user's language selection for use elsewhere.
In order to consume the language in other components, that language selection needs to be passed into the component (in this case the Header) from the Redux store.
This is the code of interest in header that does that...
const mapStateToProps = (state) => {
return {
active_language: state.active_language
}
}
export default connect(mapStateToProps)(Header)
Here you are connecting the Header to the store, with a function that describes how the store should map values into props on your react component. state.active_language is where the language that the user has selected is stored, and this is telling it to be passed as a prop called active_language on your Header component
The connect function is a decorator that will create what's know as a Higher Order Component (HOC) which is essentially a component with props or functionality automatically injected into it (decorated in this case with an automatically passed value for the active_language prop from the store)
You can do the same for any other component that need this language setting, or go a step or two further
Instead of passing the active language name, pass the corresponding language itself...
import { getLangDetails } from '../../actions/action_language'
import langObject from './Header.lang'
const mapStateToProps = (state) => {
return {
active_language: getLangDetails(state.active_language, langObject)
}
}
export default connect(mapStateToProps)(Header)
OR better yet write another HOC that wraps any component you pass with this info...
import { getLangDetails } from '../../actions/action_language'
export default const injectLanguage = (component, langObject) => connect((state) => ({
language: getLangDetails(state.active_language, langObject)
})
)(component)
Then in subsequent components with a language prop, decorate with this
import injectLanguage from './some/where'
import langObject from './MyLanguageDetailsAwareComponent.lang'
class MyLanguageDetailsAwareComponent extends React.Component {
render() {
return this.props.language
}
}
export default injectLanguage(MyLanguageDetailsAwareComponent, langObject)