react without constructor declaring state in class's body - javascript

I saw below code somewhere and I'm curious. It looks cleaned but unusual to me. Why state = {} is declared without an constructor?
and load declared without a function keyword? As I know for there are ways to write a function
function async load() {}
or
const async load = ()=>{}
And what ...args does? is it spread arguments?
import View from './View';
import loadData from './loadData';
export default class extends Component {
state = {};
load = this.load.bind(this);
async load(...args) {
try {
this.setState({ loading: true, error: false });
const data = await loadData(...args);
this.setState({ loading: false, data });
} catch (ex) {
this.setState({ loading: false, error: true });
}
}
render() {
return (
<View {...this.props} {...this.state} onLoad={this.load} />
);
}
}

The state = {} declaration is a class property, which is currently not part of the JavaScript language. Certain utilities such as Babel will compile this into legal JavaScript code.
However, the lack of a function keyword within classes, as well as the ... operator are part of ECMAScript 6, which has been officially implemented into the language (though some browsers do not recognize it yet).
Class Definition
Spread Operator

Yes, you can initialize state without a constructor for a React class component:
class Counter extends Component {
state = { value: 0 };
handleIncrement = () => {
this.setState(prevState => ({
value: prevState.value + 1
}));
};
handleDecrement = () => {
this.setState(prevState => ({
value: prevState.value - 1
}));
};
render() {
return (
<div>
{this.state.value}
<button onClick={this.handleIncrement}>+</button>
<button onClick={this.handleDecrement}>-</button>
</div>
)
}
}
It uses class field declarations which are not part of the language yet but enabled with Babel. You can checkout a sample application over here.
You can also use state in React function components (without a constructor), but using higher-order components or render prop components. You can find out more about it here.

Related

React component to return something other than jsx

I am trying to refactor some code written by someone else and was wondering if the following is possible. can I create a react component that returns non html or jsx? and returns a function or something?
basically the component so far contains 4 functions and then a return block that returns some jsx that gets rendered
I want to extract 2 of these functions out into their own component as they are similar and can be reused
however, these functions just make ajax calls and call other functions rather than returning any jsx. they also require props inside them and need the props either passed in or connected to the redux store
some of the functions it calls are dispatch functions and therefore MUST be connected to the redux store. so I cannot build a standalone function
does this make sense or am I missing something. pseudo code below to demonstrate:
const component = ({...props}) => {
const func1(){
prop1()
try{
} catch(){
callingAnotherProp()
}
}
const func2(){
}
const func3(){
}
const func4(){
}
}
imagine func1 and func2 were identical. and as you can see they don't return any jsx just make further calls.
I don't think I can isolate into a sep function. I'd rather not pass the props in as args and just connect the function to the redux store and use the props that way. is this possible?
What about HOC? You can create a component with the func1()method and the render function of this component will just return {this.props.children}.
The two other options are a standalone function (you don't like it) and inheritance (I don't like it).
Not sure i fully understand your goal here but from what i understand, you want a component that will fetch data and will expose it to other components (or child components?).
There is a nice pattern called children as a function (or render props).
Basically you treat the children passed to the component as a function and you can pass the function anything (fetched data in you case).
return this.children(this.state.data)
Here is a small running example:
class Fetcher extends React.Component {
state = { result: { data: [] } };
componentDidMount() {
const { url } = this.props;
fetch(url)
.then(response => response.json())
.then(data => this.setState({ result: { data } }))
.catch(err => this.setState({ result: { error: true, message: err } }));
}
render() {
const { children } = this.props;
return children(this.state.result);
}
}
class App extends React.Component {
renderUsers = users => users.map(user => <div>{user.name}</div>);
render() {
return (
<div>
<Fetcher url={"https://jsonplaceholder.typicode.com/users"}>
{response => (
<div>
{response.data.length
? this.renderUsers(response.data)
: "Loading..."}
</div>
)}
</Fetcher>
</div>
);
}
}
const root = document.getElementById("root");
ReactDOM.render(<App />, root);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="root"/>

React Native using setState with setParams

I'm working on a react native app where I'd like to be able to change the state from the static navigationOptions. I was following this: https://github.com/react-navigation/react-navigation/issues/1789
And have implemented one of the solutions as follows:
static navigationOptions = ({navigation}) => {
const { state } = navigation;
const {params = {}} = navigation.state;
navigation.params = {title: "", description: "", points: 0, image: {}, saveImage: true};
return {
headerRight: ( <Button transparent onPress={()=> params.create()}><Icon name="ios-add" style={{color: 'white'}}/></Button>)
};
};
componentDidMount() {
this.props.navigation.setParams({
create: this.openCreateModal
});
}
openCreateModal() {
this.setState({createModalVisible:true});
}
Unfortunately when I call the openCreateModal function by pressing the button, I get the error this.setState is not a function.
I'd appreciate any help with this.
Your openCreateModal() method is not bound. Look further down in that issue and someone points out that mistake.
To fix this, you either need to explicitly bind it so it has access to the correct this context, for example in your constructor:
constructor(props) {
super(props);
this.openCreateModal = this.openCreateModal.bind(this);
}
Or you can convert it to an ES6 arrow function which would auto-bind it to the class's context like so:
openCreateModal = () => {
this.setState({createModalVisible:true});
}

Custom function inside header button react native

I am trying to call a custom function inside a custom button in my react navigation header. I've looked around several ways to do this, and the best result I've found is making the function static, that is:
export class MyClass extends React.Component{
static navigationOptions = ({navigation}) => ({
headerRight: (<Button title='press me' onPress={()=> MyClass.SomeFunction() } ></Button>)
});
static SomeFunction(){
/*Some code here*/
}
/*Some extra code here*/
}
My issue is, however, that I need to access some state properties within SomeFunction() and, as you may know, you cannot acces this within a static function.
Is there any way I can access the state of a component within a static, or is there a better way to implement a custom function within a button in the header????
As an alternative solution you might set the navigator state to set and get values.
If you use an AppWithNavigation state parent as a root of your navigation structure you should be pass a navigation prop to children elements like below:
render() {
const { dispatch, nav, } = this.props
return (
<AppNavigator
navigation={addNavigationHelpers({
dispatch: dispatch,
state: nav,
})}
/>
)
}
If so, just set your values by using the following line:
this.props.navigation.setParams({someValue: 'Value'})
Then get your set value whenever you want like the below:
this.props.navigation.state.someValue
Or
const { someValue } = this.props.navigation.state
But keep in mind, when first rendering the component state may be null or undefined. So you need to check its existing before try to get:
if (!this.props.navigation.state) {
return null
}
const someValue = this.navigation.state.someValue
if (someValue) {
/* you can use your someValue here! */
}
Note to that every route has its own state object. When your screen is changed, the state of your this.props.navigation.state object is changed. If you need a global solution, I think, you might use Redux.
after some time messing around with the code, I found a solution that better fits my needs. I post it below in case it helps anyone. Thank you all for your contributions :D
export class MyClass extends React.Component{
static navigationOption = ({navigation}) => ({
headerRight: (<Button title='Press Me!' onPress={() => MyClass.SomeFunc() })
})
//The function
static SomeFun(){
alert(MyClass.SomeState.abc)
}
//Static functioning as state
static SomeState = {
abc: 'def'
}
}
Here is an approach straight from their documentation https://reactnavigation.org/docs/en/header-buttons.html
There is also an npm module to make this a bit easier. https://www.npmjs.com/package/react-navigation-underscore
class HomeScreen extends React.Component {
static navigationOptions = ({ navigation }) => {
const params = navigation.state.params || {};
return {
headerTitle: <LogoTitle />,
headerRight: (
<Button onPress={params.increaseCount} title="+1" color="#fff" />
),
};
};
componentWillMount() {
this.props.navigation.setParams({ increaseCount: this._increaseCount });
}
state = {
count: 0,
};
_increaseCount = () => {
this.setState({ count: this.state.count + 1 });
};
/* later in the render function we display the count */
}

React alternative components definition syntax

I am the kind of person that do not see positively the "class" keyword in the Javascript language as I feel that it does not fit well with the underlying object model. To create objects, I also prefer factories over "new" and constructor functions.
Besides, I really like React. So I have come up with a way of defining components that completely avoids the whole "class" and "extends" thing and only uses functional components or component factories. It also completely avoids to have to bind class methods or to use tricky class properties defined as arrow functions (for event handlers defined as class methods).
Before describing it, here is my question: is it future-proof to use this syntax, or will React one day force me to use a syntax that I do not approve?
Here is how I define components depending on the needs :
Components that only depend on their props are written as functional components (function that returns JSX):
const Comp = (props) => (
<p> Hey { props.name } </p>
);
Comp.propTypes = {
name: PropTypes.string.isRequired
};
Components for which one wants to use lifecycle hooks but that do not maintain any state are written as a function that creates and returns an object whose members are the props, the needed lifecycle methods and the render method:
const Comp = (props) => ({
props,
componentWillMount() {
this.props.doSomething();
},
render() {
return (
<p> Hey { this.props.name } </p>
);
}
});
Comp.propTypes = {
doSomething: PropTypes.function.isRequired,
name: PropTypes.string.isRequired
};
Components that need to maintain state are written as a function that creates and returns an object whose prototype is React.Component (to gain the setState function) and whose members are the props, the state, the needed lifecycle methods and the render method. Functions called by the interface are defined in this factory function closure and act on the component (mainly setState) directly using the component instance (no binding problem here):
const Comp = (props) => {
const comp = Object.create(React.Component.prototype);
const handleClick = () => {
comp.setState((prevState) => ({ value: prevState.value + 1 }));
};
return Object.assign(comp, {
props,
state: { value: 4 },
componentWillUpdate() {},
render() {
return (
<p> Hey { this.props.name } </p>
<p> Value: { this.state.value } </p>
<button onClick={ handleClick }> Increment </button>
);
}
});
};
Comp.propTypes = {
name: PropTypes.string.isRequired
};

Having trouble listing down state map or prop map in React

Here is whats inside my tbody tag:
{this.props.listingData.map((listingData,index) =>
<tr key={index}>
<td>{listingData.location_id}</td>
<td>{listingData.location}</td>
<td>{listingData.description}</td>
</tr>
)}
I'm getting map of undefined error.
Tried logging this.props.listingData & it works.
Here is sample map data which I used:
[{"location_id":1,"location":"HKG","description":"Hong Kong","update_by":null,"update_time":null,"create_by":null,"create_time":null,"rec_state":0},{"location_id":2,"location":"KUL","description":"Kuala Lumpur","update_by":null,"update_time":null,"create_by":null,"create_time":null,"rec_state":0}]
Should be working?
My getDefaultProps:
getDefaultProps() {
return {
//value: 'default value' //called as this.props.value
listingData: [{"location_id":1,"location":"HKG","description":"Hong Kong","update_by":null,"update_time":null,"create_by":null,"create_time":null,"rec_state":0},{"location_id":2,"location":"KUL","description":"Kuala Lumpur","update_by":null,"update_time":null,"create_by":null,"create_time":null,"rec_state":0}]
};
}
Tried this and still getting the error.
You have to define the default props that is a good practice when creating you component, according to the document https://facebook.github.io/react/docs/reusable-components.html#default-prop-values:
var MyComponent = React.createClass({
getDefaultProps: function() {
return {
listingData: []
};
},
render: function () {
//...
}
});
or es2015
class MyComponent extends React.Component {
render() {
//...
}
}
MyComponent.defaultProps = {
listingData: []
}
with static property support
class MyComponent extends React.Component {
static defaultProps = {
listingData: []
};
render() {
//...
}
}
Sounds like you're performing an asynchronous fetch and passing the response as a prop to this component. This means that the first time the component is rendered, it will be undefined (try putting a breakpoint inside render and see for yourself).
As you've seen, you can't call map on undefined, so you need to return something else if you don't have the data yet. Personally I prefer something along these lines:
if (!this.props.listingData) return null;
return this.props.listingData.map(listingData => // ...
There are clearly other ways you can write this. Alternatively, you can provide default props.
Note if location.id is unique, you should use that as your key, rather than the loop index.

Categories

Resources