I can't figure out how to use multiple states in a single React component, since I can't call useState in a class.
What I need to achieve is to have multiple states and "monitor" them with useEffect independently.
Currently I have something like this, but from what I understand I can't have anything like useEffect based solely on object fields. How should I go about this?
class ShowPosts extends Component {
constructor(props) {
super(props);
this.state = {
posts: [],
sorting:'desc',
lastPostDate:'none',
hasMore:false,
pageNumber:1
};
}
class ShowPosts extends Component {
constructor(props) {
super(props);
this.state = {
posts: [],
sorting:'desc',
lastPostDate:'none',
hasMore:false,
pageNumber:1
};
componentDidUpdate(prevProps, prevState, snapshot){
//write the code to monitor this.state and prevState in here
}
}
ComponentDidUpdate is called after every render. This will be same as useEffect for functional components.
Related
I read on the internet that it is a bad bad coding practice to perform the following:
class Test extends React.Component {
constructor(props) {
super(props);
this.state = {
someItem = props.someItem
};
}
}
However, if I had this scenario instead:
class Test extends React.Component {
constructor(props) {
super(props);
this.state = {
someItem = this.props.someItem
};
}
}
Test.propTypes = {
someItem: PropTypes.array
};
function mapStateToProps(state, ownProps) {
[...]
return {
someItem: someItem
};
}
export default withRouter(connect(mapStateToProps)(Test));
Will there be an issue? Cannot find anywhere on the net that does not say that i cannot do that.
I am trying to ensure that everytime i navigate back to this component, the component is able to get the data from the Redux Store. I tried using componentWillReceiveProps(), but so far it only runs once and componentDidMount and componentWillMount does not accept setState.
Cheers.
You should not save props in state unless and until you would want to modify it at a later point in time locally and update it after some action to the provider of props. In short you state must not be directly derivable from props at all points of time in your code.
Even though you use redux mapStateToProps to provide props to component, its still the same as coming from parent
class Test extends React.Component {
render() {
console.log(this.props.someItem);
}
}
Test.propTypes = {
someItem: PropTypes.array
};
function mapStateToProps(state, ownProps) {
[...]
return {
someItem: someItem
};
}
export default withRouter(connect(mapStateToProps)(Test));
who knows how change props in my component use refs in react js ?
<MyComponent
ref={'input1'}
name={'input1'}
label={interestsName}
disabled={ false}
onChange={this.myFunction}/>
after onChange i call function with
myFunction =()=>{console.log(this.rews[input1].props.disable);}
May I change props use refs without use state? Because I have many '15' components such as this component. Thanks.
You cannot change props from child class, for more please refer to link.
For your functionality use you can use state to change value on the change event. And one more thing you should keep the logic of changing component properties should remain inside a component. This will help us to maintain different states for different components.
class MyComponent extends React.Component {
constructor(props) {
this.state = {
disable: props.disabled
};
}
myFunction() {
console.log(this.state);
}
}
You can iterate over the above component and it can be used for 15 times and different states can be managed for every element
You shouldn't use ref in this case, you should use states to change your child props:
class MainComponent extends React.Component {
constructor(props) {
super(props)
this.state = {
disable: false,
};
this.onChange = this.onChange.bind(this);
}
onChange() {
this.setState({ disable: true });
}
<MyComponent
name="input1"
label={interestsName}
disabled={this.state.disable}
onChange={this.onChange}
/>
}
In <MyComponent> use componentWillReceiveProps() to detect new props value.
class RaisablePaper extends Component {
constructor(props) {
super();
this.state = {
state1: "state1",
openNow: props.boxOpen,
};
}
}
I am trying to send value to this class by doing <RaisablePaper boxOpen={this.state.dOpen}/>. But whenever the dOpen gets changed it does not seem to update the openNow. Help would very much appreciated.
You are setting the state before mounting the component in the constructor, which will not be fired again when the props change. For that you can use React's componentWillReceiveProps, which will be called when new props are sent to the component.
class RaisablePaper extends Component {
constructor(props) {
super();
this.state = {
state1: "state1",
openNow: props.boxOpen
};
}
componentWillReceiveProps(props) {
this.setState({
openNow: props.boxOpen
});
}
}
It would be simpler to use the props directly instead of worrying about syncing it to your state. It's a good idea in general to rely on props as much as possible, and only involve state when absolutely necessary.
But Fabian Schultz is absolutely right -- your constructor only runs once, before the component is mounted, so you'll never receive the subsequent updates if the component is relying on state which is initialized during construction.
I'm just imagining how you're using the boxOpen state to show an example; you can follow the same general idea with whatever your render method is doing.
class RaisablePaper extends Component {
render() {
return (
<div className={this.props.boxOpen ? 'is-open' : ''}>
Here's some content...
</div>
);
}
}
I'm using Mongo/Meteor 1.3/React. In my simple example I use an wrapper React component to query the Mongo collection and create an Array. When passing to the Child component, it seems like the Array object is not ready when constructor is called - meaning I can't access the props.
This feels like it must be a common problem. Should I be using a different React Lifecycle Component? Or adding some form of waitOn function? Any advice appreciated!!
Parent Component
export default class BulkMapWrapper extends TrackerReact(React.Component) {
constructor() {
super();
const subscription = Meteor.subscribe("listing",{sort: {_id:-1}})
this.state = {
eventsData: subscription
}
}
render () {
var markerArray = []
markerArray = ...
return(
<div className="panel panel-default">
<div className="panel-body">
<FourthMap
mapParams = {manyEvents}
markers = {markerArray}
/>
</div>
</div>
)
Child Component
export default class GooleMapComponent extends Component {
constructor(props){
super(props)
console.log(this.props.markers);
You should use the componentDidMount function to get the data and then set a new state with the resulting data.
class GetData extends React.Component {
constructor(props) {
super(props);
this.state = {};
}
componentDidMount() {
const subscription = Meteor.subscribe("listing",{sort: {_id:-1}});
this.setState({
eventsData: subscription
});
}
}
You can then pass down the state from the GetData component as props to its children or explicitly to another component in the render function.
This is generally how you should handle AJAX requests in React but I'm not sure if this will translate well to use in Meteor.
I'm trying to use a stateful React component with ES6 but when I define a constructor the constructor will only be called once while the component is rendered multiple times (from its parent). Example shown below.
class SubComponent extends React.Component {
constructor(props) {
super(props);
console.log("Creating sub component");
this.state = { count: props.count };
}
render() {
console.log("Rendering sub component", this.state.count);
return (<div>count: {this.state.count}</div>);
}
}
class App extends React.Component {
constructor(props) {
super(props);
console.log("Creating app");
this.state = { count: 0 };
this.tick = this.tick.bind(this);
setInterval(this.tick, 1000);
}
tick() {
this.setState({ count: this.state.count + 1 });
}
render() {
console.log("Rendering app", this.state.count);
return (<SubComponent count={this.state.count} />);
}
}
This will not update the rendered output (it will always be count: 0) but the logs will output:
Creating app
Rendering app 0
Creating sub component
Rendering sub component 0
Rendering app 1
Rendering sub component 0
Rendering app 2
Rendering sub component 0
Rendering app 3
Rendering sub component 0
...
Here's a JSFiddle: http://jsfiddle.net/jor0xu1a/1/
I'm aware that the example SubComponent doesn't need a state but I tried making it as simple as possible to show my problem.
What am I missing?
In SubComponent it is props not state - change it to this.props.count and this will work
I recommend to read Props in getInitialState Is an Anti-Pattern.
Basically, as few components as possible should have state. As the other answers already said, in your case you can just use this.props.count to refer to the current value. There doesn't seem to be any reason why SubComponent should have its own state.
However, if you really want to compute the component's state from the props it receives, it is your responsibility to keep them in sync, with the life cycle method componentWillReceiveProps:
componentWillReceiveProps(nextProps) {
this.setState({count: nextProps.count});
}
You SubComponent should be:
class SubComponent extends React.Component {
constructor(props) {
super(props);
console.log("Creating sub component");
}
render() {
return (<div>count: {this.props.count}</div>);
}
}
My bad, I thought that the constructor (or getInitialState for ES5) is called whenever the component is being re-rendered by the parent (I thought that the parent 're-creates' its children on render) but that's not always the case. I should had read up on it (url) and tried it with ES5 (jsFiddle) before thinking it was something I didn't understand with ES6 and creating a question here.
And yes, the example SubComponent should use this.props but my use case had actual stateful functionality in my real component. I created the example as I thought for some reason that the result weren't the expected outcome when using ES6 (but it was).
Thank you for you feedback!