The function call isn't working inside the React component - javascript

In the following, JSON data is fetching successfully from a parent component but the function breakLine() doesn't work when called inside the component, throwing the following error message.
'breakLine' is not defined no-undef
json.db
{
"studies": [
{
"text": [
"first line here-=br=-second line here"
]
}
}
component code:
import React, { Component } from 'react'
class PortfolioPage extends Component {
constructor(props) {
super(props);
this.state = {
resultText: []
}
}
componentDidMount() {
this.setState({
resultText: this.props.data.text
})
}
breakLine(text){
text.replace("-=br=-", "\n");
}
render() {
const { resultText } = this.state;
return (
<div className="portfolio-pages">
<p>
{breakLine(resultText)}
</p>
</div>
)
}
export default PortfolioPage

you need to bind this function to the context. try to use
class PortfolioPage extends Component {
constructor(props) {
...
this.breakLine = this.breakLine.bind(this)
}
or arrow style
breakLine = (text) => {...}

Bind the function to current context and use this keyword:
breakLine = (text) => text.join(' ').replace("-=br=-", "\n");
// [...code...]
{this.breakLine(resultText)}

The this. is missing, you should call it with this.breakLine(resultText).
Though your resultText is of type string[], so you will want to define the breakLine function as follows:
text.map(t => t.replace("-=br=-", "\n"))
if you want to have one line per array item, you could also do the following:
text.join("\n").replace("-=br=-", "\n").split("\n")

Related

How can I append an item to a list in js in reactjs

I created a Parent Component js file and changed the state fo numbers list by adding 10 to it but it is showing error as there is no push funtion.Could anyone help me with this??
import React, { Component,PureComponent } from 'react'
import Reg from './Regularcomp'
import Pure from './PureComp'
export class Parentcomp extends PureComponent {
constructor(props) {
super(props)
this.state = {
name:"Mayank",
numbers:[1,2,3,4,5,6]
}
}
componentDidMount()
{
setInterval(()=>{
this.state.numbers = this.state.numbers.push(10)
},1000)
}
render() {
console.log("*****Parent Component*******")
return (
<div>
Parent is Pure Component
<Reg name={this.state.name}/>
<Pure name={this.state.name}/>
</div>
)
}
}
export default Parentcomp
state interface in react class components is a complex structure. It doesn't provide you any plain setters on your data structrue. The only setter you may use on it is setState method. So you should rewrite your componentDidMount as:
componentDidMount() {
setInterval(() => {
this.setState((prevState) => ({
numbers: [...prevState.numbers, 10]
}));
}, 1000);
}

ReactJs: Passing url param to outside functions

I'm working on an Isomorphic react application using redux. I'm having issues passing a url parameter into a function that dispatches a redux action.
class SingleMovie extends Component {
componentDidMount(){
console.log(this.props.match.params.id); // i can access the id here
}
.....
}
function mapStateToProps(state){
return {movie:state.movie};
}
function loadData(store, id){ //<--how do i get the id parameter
return store.dispatch(fetchMovie(id)); //<--so i can pass it here
}
export default {
loadData,
component: connect(mapStateToProps,{fetchMovie})(SingleMovie)
};
What i tried:
(1) Declare a constant outside the React component
let id = "";
class SingleMovie extends Component {
...
(2) Try to assign the global variable with the id
componentDidMount(){
id= this.props.match.params.id;
}
The id always ends up being undefined.
First save the id params to the state, and then use setState's callback function to dispatch the fetchMovie action.
class SingleMovie extends Component {
constructor(){
this.state = {
id: ""
}
}
componentDidMount(){
//console.log(this.props.match.params.id);
this.getMovieId(this.props.match.params.id);
}
getMovieId = (movieId) => {
this.setState({
id: movieId
}, () => {
this.loadData();
})
}
loadData = (store) => {
store.dispatch(fetchMovie(this.state.id));
}
render(){
return(
...
)
}

Pass data from react.js Store to Component in a clean way following flux pattern

following the Flux pattern I'm trying to update my component and pass some values (a string and a boolean in this specific case) via the store.
I could not find any non-hacky way to solve this yet i.e. using global vars in the Store and use a getter function in the Store which is called from the component on ComponentWillMount(), not a nice solution.
Here's a stripped down code example to show what im trying to achieve:
ExampleStore.js
import AppDispatcher from '../appDispatcher.jsx';
var displayimportError = false;
var importedID = '';
import axios from 'axios';
class ExampleStore extends EventEmitter {
constructor() {
super();
}
importId(id) {
let self = this;
// fetch data from BE
axios.get('foo.com').then(function(response) {
if (response.data && response.data.favoriteEntries) {
displayimportError = false;
}
self.emitChange();
}).catch(function(error) {
console.log(error);
displayimportError = true;
importedID = id;
self.emitChange();
// now update component and pass displayimportError and
// importedID.
// best would to component.receiveUpdateFromStore(param); but
// it's giving receiveUpdateFromStore is not function back
});
}
}
var favObj = new ExampleStore();
AppDispatcher.register(function(payload) {
var action = payload.action;
switch (action.actionType) {
case 'UPDATE_ID':
favObj.importId(action.data);
break;
}
return true;
});
export default favObj;
As mentioned in the Comment above the best solution in my eyes so far would be to call a function in the component from the store i.e component.receiveUpdateFromStore(param); and then update the component state within that function but even though they seem to be im/exported correctly to me it is returning receiveUpdateFromStore is undefined.
Any other idea how to solve this is appreciated.
//example component
import React from 'react';
import ReactDom from 'react-dom';
import ExampleStore from '../stores/ExampleStore.jsx';
class ExampleComponent extends React.Component {
constructor(props) {
super(props);
}
receiveUpdateFromStore(param) {
this.setState({'exampleText': param.text, 'exampleBoolean': param.bool});
}
render() {
return <div className="foo">bar</div;
}
}
export default ExampleComponent;
Any idea how to pass data from store to a component and update component state in a nice way?
I would hang your store state on the store class instance itself -- something like this.state.displayimportError = true -- and then have the component subscribe to the store:
import React from 'react';
import ExampleStore from '../stores/ExampleStore.jsx';
class ExampleComponent extends React.Component {
constructor(props) {
super(props);
this.state = {
importError: ExampleStore.state.displayimportError,
};
}
componentWillMount() {
ExampleStore.on( 'change', this.updateState );
}
componentWillUnmount() {
ExampleStore.removeListener( 'change', this.updateState );
}
updateState = () => {
this.setState( state => ({
importError: ExampleStore.state.displayimportError,
})
}
render() {
return <div>{ this.state.importError }</div>
}
}
NOTE: Above code untested, and also using class properties/methods for binding updateState.

Move function in React from component to referenced library

I'm learning React and I'm not sure how to setup this pattern. It could be something really easy I'm just missing.
I have a main component that controls state. It has all of the functions to update state and passes these down to child components via props. I've simplified the code to focus on one of these functions.
Here's the component now, all works as it should:
ManageMenu.js
import React from 'react'
class ManageMenu extends React.Component {
constructor() {
super()
this.toggleEditing = this.toggleEditing.bind(this)
// Set initial state
this.state = {
menuSections: []
}
}
toggleEditing(id) {
const menuSections = this.state.menuSections
menuSections.map(key => (key.id === id ? key.details.editing = id : ''))
this.setState({ menuSections })
}
render() {
return (
...
)
}
}
export default ManageMenu
The toggleEditing is passed via props to a child component that uses it to render an editing form if the edit button is clicked.
I have about 10 of these different functions in this component and what I would like to do is move them to an external lib/methods.js file and then reference them. Below is the code I would like to have, or something similar, but React doesn't like what I'm doing. Throws a syntax error:
Failed to compile.
Error in ./src/components/ManageMenu.js
Syntax error: Unexpected token
toggleEditing(id, menuSectionId, this.state, this)
Here is what I would like to do...
lib/methods.js
const toggleEditing = function(id, state, that) {
const menuSections = state.menuSections
menuSections.map(key => (key.id === id ? key.details.editing = id : ''))
that.setState({ menuSections })
}
module.exports = {
toggleEditing
}
And then in my component:
ManageMenu.js
import React from 'react'
import { toggleEditing } from '../lib/methods'
class ManageMenu extends React.Component {
constructor() {
super()
// Set initial state
this.state = {
menuSections: []
}
}
toggleEditing(id, this.state, this)
render() {
return (
...
)
}
}
export default ManageMenu
Any help is appreciated, thanks!
Thanks to #Nocebo, the answer on how to externalize functions is here:
Externalise common functions in various react components
In my particular situation,
I need to remove the “floating” toggleEditing(id, this.state, this) call in the middle of nowhere. Update: This error happens “because it is invoking a method within a class definition.” (see Pineda’s comment below)
Remove the leading this. on the right side of the this.toggleEditing statement in constructor()
Update the function in lib/methods.js to remove the state and that variables since its bound to this in the constructor()
See updated code below.
ManageMenu.js
import React from 'react'
import { toggleEditing } from '../lib/methods'
class ManageMenu extends React.Component {
constructor() {
super()
this.toggleEditing = toggleEditing.bind(this)
// Set initial state
this.state = {
menuSections: []
}
}
render() {
return (
...
)
}
}
export default ManageMenu
lib/methods.js
const toggleEditing = function(id) {
const menuSections = this.state.menuSections
menuSections.map(key => (key.id === id ? key.details.editing = id : ''))
this.setState({ menuSections })
}
module.exports = {
toggleEditing
}
You're error arises because you are invoking toggleEditing in your ManageMenu.js class definition rather than defining a function.
You can achive what you want by setting a local class member this.toggleEditing to the bound function returned by the .bind method and do so within the constructor:
import React from 'react'
import { toggleEditing } from '../lib/methods'
class ManageMenu extends React.Component {
constructor() {
super()
this.state = {
menuSections: []
}
// bind external function to local instance here here
this.toggleEditing = toggleEditing.bind(this);
}
// don't invoke it here, bind it in constructor
//toggleEditing(id, this.state, this)
render() {
return (
...
)
}
}
export default ManageMenu

React HOC to handle clicks outside a given Component

I desire to make a Higher Order Component to manage outside clicks. When it is determined that a user has clicked outside a given component a certain passed function should execute. This HOC takes 2 parameters:
BoundaryComponent: the component we are interested in determining if clicks are outside of it
onOutsideClick: a function to execute when a click occurs outside the component
This ClickOutside component looks like:
import React from 'react'
const { Component } = React
import { findDOMNode } from 'react-dom'
export default function ClickOutside (BoundaryComponent, onOutsideClick) {
return class Wrapper extends Component {
constructor (props) {
super(props)
}
componentDidMount() {
document.addEventListener('click', this.handleClick.bind(this), true)
}
componentWillUnmount() {
document.removeEventListener('click', this.handleClick.bind(this), true)
}
render () {
const props = Object.assign({}, this.props, { ref: this.getContainer.bind(this) })
return (
<BoundaryComponent
{...props}
/>
)
}
getContainer (wrapped) {
this.container = findDOMNode(wrapped)
}
handleClick(e) {
if (this.container && !this.container.contains(e.target) && typeof onOutsideClick === 'function') {
onOutsideClick()
}
}
}
}
And I am trying to utilize this component like this:
import React from 'react'
const { ClickOutside } = 'utils/click-outside'
import { updatePicklistActiveIndex } from 'components/store/actions'
import { getPicklistActiveIndex } from 'components/store/selectors'
import PickList from 'components/picklist'
// ...
function mapDispatchToProps (dispatch) {
return {
updatePicklistActiveIndex: (activeIndex) => { dispatch(updatePicklistActiveIndex(activeIndex)) },
}
}
function mapStateToProps (state) {
return {
picklistActiveIndex: getPicklistActiveIndex(state),
}
}
let onOutsideClick = null // This feels like a code smell
class DropdownPickList extends PickList {
constructor(props) {
super(props)
this.state = {
dropdownVisible: false,
}
onOutsideClick = () => {
this.props.updatePicklistActiveIndex(-1)
this.setState({ dropdownVisible: false })
}
}
// ...
render() {
return (
//...jsx to render DropdownPickList
)
}
}
const pickList = ClickOutside(DropdownPickList, () => { onOutsideClick() })
export default connect(mapStateToProps, mapDispatchToProps)(pickList)
The above implementation works as I would expect...
But defining onOutsideClick outside the context of the DropdownPickList Class, and then overwriting this variable reference within the constructor of this Class just feels wrong. But it seems to be the only way to get access to the props and state within the class needed to close the dropdown.
I also tried using a static method in the DropdownPickList class to handle the onOutsideClick, but the problem with this is this Class is passed as an unrendered component, so I do not have access to any of its instance methods in my handleClick of the HOC.
There must be a better way to do this? Any help or alternative implementation ideas/patterns would be greatly appreciated!
Instead of creating a function, just export the wrapper and change as the following :
BoundaryComponent : move to be the children of the wrapper (so it will be actually a wrapper) like so :
<Wrapper>
<BoundaryComponent />
<Wrapper>
While inside wrapper you will render {this.props.children}
onOutsideClick: the onOutsideClick function move to the props of Wrapper :
<Wrapper onOutsideClick={this.onOutsideClick}>
<BoundaryComponent />
<Wrapper>

Categories

Resources