I'm trying to adapt code from a SO answer, with functions and variables written as below:
const getIntervals = n=> availability=> {
}
let availability = [
]
Are those normally fine to use in a react class (see below) or do they need to be rewritten?
class Calendar extends React.Component {}
The reason for asking is that I use a React implementation for Rails and do get an error including that function and variable naming pattern.
Pure Functions, which dont modify the passed value, are always fine to use anywhere.
Its also fine to use them in a React Class directly, but common functions like string modifications, array sorting algorithms, which you are using a lot across your app and classes should go in a separate module like
// my-helpers.js
export const countKeysInObject = (data) => {
if (typeof data !== "object" || Array.isArray(data)) return 0;
Object.keys(data).length;
}
some other file..
import { countKeysInObject } form 'my-helpers'
// And you can use it everywhere..
If you are using class and extending Component, you can use simple methods for most things:
class Calendar extends React.Component {
constructor(props) {
this.date = props.date;
}
render() {
return <span>{this.date.toString()}</span>;
}
}
Calendar.propTypes = {
date: React.PropTypes.date.isRequired
};
You cannot use methods for propTypes or anything that would be an initial field if you were using an object literal. Those need to be attached after the class has been declared (propTypes) or in the constructor (initial state).
Related
Please advise how to solve the following problem:
There is a component that outputs some counter:
#observer class MyComponent extends React.Component {
render() {
const data: MyData = new MyData();
return <div>{data['counter']}</div>;
}
}
The counter is stored in a trackable (via mobx #observable) singleton:
export class MyData extends ISingleton
{
#observable data: any = {}
}
At some point the counter (when MyComponent is already created) the counter is set
let data: MyData = new MyData();
data['counter'] = 123;
But MyComponent is not redrawn, although the component seems to track variable change (via mobx #observer and #observable)
Please advise where is the error and how can it be fixed
In mobx you need manipulate the state of observers within actions.
You should extend your singleton to look something like this:
export class MyData extends ISingleton
{
#observable data: any = {}
#action
setCounter(val: number) {
this.data = val
}
}
Then call the setCounter-Method instead of manipulating the state directly.
Please take note that as of version 6 of MobX it is discouraged to use the decorator API (see this for more information).
Every render creates a completely fresh new data object, effectively resetting it. So you want to store data at the class instance, not inside the render. Also the data you are modifying is completely different data than the data you are rendering (that is what the new keyword does). Probably you want to read up a little on how objects, classes & instances work in JavaScript in general
Today I did a review for my colleague and I found a function definition that interested me. He implemented a function inside a react component with default parameter values if the function call is not provided with an argument. He used a state value as a default parameter.
It looked like this example:
class CustomComponent extends React.Component {
constructor(props) {
this.state = {
loadedData = [], // array of objects
};
this.filterDates = (fromUtc, toUtc, loadedData = this.state.loadedData) {
// do something with 'loadedData' based on time range 'fromUtc' and 'toUtc'
}
}
}
He could not provide me a good explanation. Only that it works in his implementation.
I have always used 'static' default parameter values (like [], number, etc.)
I am curious if it is ok to use some kind of 'dynamic' default parameter, which changes when state changes.
Is it ok to write it like this? Could be there a problematic case?
According to Airbnb Javascript Style Guide -es6 default parameters this approach is good. However I question assigning default value to state which is mutable by definition unless it's desired effect. Default parameter shouldn't be mutable. Personally I see such approach for the first time and I think it's not intuitive but maybe it's just my experience.
In my opinion code below is cleaner, easier to understand and less buggy:
class CustomComponent extends React.Component {
constructor(props) {
this.state = {
loadedData = [], // array of objects
};
this.filterDates = (fromUtc, toUtc, loadedData = []) => {
// do something with 'loadedData' based on time range 'fromUtc' and 'toUtc'
}
}
}
In the constructor, this.state is a simple object without any magical feature of states. So, loadedData = this.state.loadedData is the same as loadedData = [] but the second one is more readable.
I mostly see JavaScript use classes as a constructor as following:
class Rectangle {
constructor(height, width) {
this.height = height;
this.width = width;
}
// Getter
get area() {
return this.calcArea();
}
// Method
calcArea() {
return this.height * this.width;
}
}
What's the reason React uses classes without using the contructor() function, such as following? I don't see classes being used to create instances.
class App extends Component {
render() {
return (
<div className="app-content">
</div>
)
}
}
Right now you should use classes in React if you need to use "advanced" component lifecycle methods like shouldComponentUpdate() or such.
Previously class components were used to handle local state in them. Right now we have Hooks API which allows to use state in a more elegant way and without need of class components.
If you want more details, you can read the article by Dan Abramov: How Are Function Components Different from Classes?.
Regardless your example, you're right, this code:
class App extends Component {
render() {
return (
<div className="app-content">
</div>
)
}
}
can be written as:
function App() {
return <div className="app-content"></div>
}
What's the reason React uses classes without using the contructor() function
From the JavaScript class doc:
If you do not specify a constructor method, a default constructor is used.
So a constructor exists for every class whether a constructor method is specified or not.
I don't see classes being used to create instances.
React components implemented as classes get instantiated by React as part of the rendering process.
Specifically, in the new React Fiber creating an instance of a React class component happens on this line of the source code.
But yes, #vicondin is right that the simple component from the question can be implemented as a function component, that class components used to be the only way to maintain state, implement lifecycle methods, etc., and that the new Hooks makes it possible to...
use state and other React features without writing a class.
In React, state is used in a React class component. There you can set initial state in the constructor of the class, but also access and update it with this.state and this.setState, because you have access to the class instance by using the this object.
If you use class in React component, even without using constructor() you can set initial state like below:
class App extends Component {
state = {
hello: 'Hello'
};
onClickHello = value => {
this.setState({ hello: 'Why did you clicked?' });
};
render() {
return (
<div className="app-content" onClick={this.onClickHello}>
{this.state.hello}
</div>
)
}
}
Another advantage is you can make use of all the React lifecycle methods
Update: After React16, you can use the lifecycle events even in function components using react hooks
Also biggest reason is the handling of state and lifecycle(componendDidMount ..etc) , class can do everything functions can , but at the cost of readability and statelessness . But in the most cases I rarely use classes only if I need a complex parent component with lifecycle
Greetings fellow denizens of StackOverflow. I am trying to write a react component which allows users to select a number (rating) from a drop down menu, which is then display and tracked persistently. However, I have a small problem. The computer doesn't like the "===" in my if statement. It says its an "unexpected token." What's the deal? Here's the if statement and everything that comes before it since I assume you don't need the rest.
import React, { Component } from "react";
const loggedRatingVar = localStorage.getItem("rating0");
class DropDown0 extends Component {
if (loggedRatingVar === null)
{
this.setState({displayRating: "?"});
}
else
{
this.setState({displayRating: loggedRatingVar});
}
Classes are not functions. Classes are not executable. Classes are CONTAINERS. They contain constructors, methods and properties. Any code inside a class has to be inside a method or constructor. (Well, the constructor is just a special method.)
This is basic JavaScript syntax and you'd do well to study the examples.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes
You are defining a class component not a function.
I suggest to read the documentation here on how to do it properly.
Since it seems you are setting states you would want to put that on a function or React lifecycle methods (more about lifecycle methods here)
Do it like so. Just gave an example on what Jaromanda X commented.
class DropDown0 extends Component {
thisIsAfunction() {
if (loggedRatingVar === null)
{
this.setState({displayRating: "?"});
}
else
{
this.setState({displayRating: loggedRatingVar});
}
}
}
The docs for React state that component functions can be accessed by a parent component via refs. See: https://facebook.github.io/react/tips/expose-component-functions.html
I am attempting to use this in my application but run into an "undefined is not a function" error when the child function is called. I'm wondering if this has anything to do with using the ES6 format for React classes because I don't see any other differences between my code and the docs.
I have a Dialog component that looks like the following pseudocode. The Dialog has a "Save" button that calls save(), which needs to call the save() function in the child Content component. The Content component collects information from child form fields and performs the save.
class MyDialog extends React.Component {
save() {
this.refs.content.save(); <-- save() is undefined
}
render() {
return (
<Dialog action={this.save.bind(this)}>
<Content ref="content"/>
</Dialog>);
}
}
class Content extends React.Component {
save() {
// Get values from child fields
// and save the content
}
}
I could instead pass a prop (saveOnNextUpdate) down to Content and then execute save whenever it is true, but I would rather figure out how to get the method detailed in the React doc above to work.
Any ideas on how to get the doc approach to work or access the child component function in a different way?
Redux connect accepts an option parametre as the forth parameter. In this option parameter you can set the flag withRef to true. Then you can access functions to refs by using getWrappedInstance(). Like this:
class MyDialog extends React.Component {
save() {
this.refs.content.getWrappedInstance().save();
}
render() {
return (
<Dialog action={this.save.bind(this)}>
<Content ref="content"/>
</Dialog>);
}
}
class Content extends React.Component {
save() { ... }
}
function mapStateToProps(state) { ... }
module.exports = connect(mapStateToProps, null, null, { withRef: true })(Content);
Read more about it here: https://github.com/reactjs/react-redux/blob/master/docs/api.md#connectmapstatetoprops-mapdispatchtoprops-mergeprops-options
Worth reading this article about use of refs and consider if there's better approaches: https://facebook.github.io/react/docs/refs-and-the-dom.html#dont-overuse-refs
An alternative way to do this would be to use some other prop name (other than ref). I've found that this also works well if you're using a library like styled-components or emotion For example in a connected MyComponent:
<MyComponent
...
innerRef={(node) => { this.myRef = node; }}
/>
As it turns out, m90 was right -- this was a different issue entirely. I'm posting the solution in case someone runs into the same problem in the future.
My application is built with Redux, and the problem stems from using the react-redux connect function to connect a component to the store/global state. For some reason, exporting a component and connecting it to the store makes it impossible to access the functions inside of it. In order to get around this, I had to remove all use of global state from Content so that I could export it as a "dumb" component.
To be more clear, Content.js looked like this:
var connect = require('react-redux').connect;
class Content extends React.Component {
save() {
// Get values from child fields
// and save the content
// Use of this.props.stateObject
}
}
function mapStateToProps(state) {
const {
stateObject
} = state;
return {
stateObject
};
}
module.exports = connect(mapStateToProps)(Content);
Removing the use of global state (and therefore the use of connect and mapStateToProps allowed me to export the component using:
module.exports = Content;
Accessing this.refs.content.save() magically worked after doing this.