Stateless functional component updates while stateful version does not - reactjs

I get data from and API async and, I thought, solved the related timing issues here, but I still have issues with the render not updating.
Since my component would not update I broke it down to a basic stateless version and then it started working. I've tried to make identical versions of the components, +/- state. Only the stateless version works as I said, but I need the full component to work so I can do stuff with the state. Otherwise I'd use it as is, stateless.
(Side note: Not sure if this is 'React-ful', but I use only props in the example in the full React.Component, never setting anything to state. Moving on...)
Full version component - unworking fiddle
class Posts extends React.Component {
constructor(props) {
super(props)
this.state = {};
this.posts = props.data;
}
render() {
return this.posts.map((post, index) => {
return (
<div className="comment" key={index}>
<div className="by">{post.by}</div>
<div className="id">{post.id}</div>
</div>
)
})
}
}
stateless functional - working fiddle
function Posts(props) {
let posts = props.data;
return posts.map((post, index) => {
return (
<div className="comment" key={index}>
<div className="by">{post.by}</div>
<div className="id"> {post.id}</div>
</div>
)
})
}
For some reason the full component does not re-render on click while the stateless does. I thought I resolved the timing issues but perhaps not? Is the component type truly causing the thing to break/work? Why?
I tried to make the only difference btw the fiddles the way Posts is structured, still the fiddles are quite busy. Hopefully though more effective in showing my problem than showing the code here.

Cause component will re-render when props or state update. In your state full component constructor only invoke once. So this.post not updated. You can fix that in 2 way
Change this.posts when props component will change
componentWillReceiveProps (nextProps) {
this.posts = nextProps.posts
}
Or use directly props.post in render (this better)
return this.props.posts.map((post, index) => {...})

class Posts extends React.Component {
constructor(props) {
super(props)
this.state = {};
}
render() {
return this.props.data.map((post, index) => {
return (
<div className="comment" key={index}>
<div className="by">{post.by}</div>
<div className="id">{post.id}</div>
</div>
)
})
}
}
First of all try something like this instead of initializing the posts in constructor. In your case it might me trying to render before initializing this.posts

Related

How to correctly initialize a function in React?

tell me, please, how to solve the following problem correctly?
I have a certain component, there is a control above, when I click on it, setState is triggered. I need to call the function this.setScrollLeft () in which I set to the selected node (ref) in this case the cleavage position.
Here is my implementation, but I am sure that there is a better solution:
import React from 'react';
import { ScoreCell, getScoreTheme } from 'components/scores';
class LeaderboardPlayerResult extends React.Component {
constructor(props) {
super(props);
this.containerWidth = 198;
this.data = this.props.data;
this.playerResultRef = React.createRef();
}
componentDidMount() {
this.element = this.playerResultRef.current;
this.element.scrollLeft = this.containerWidth;
}
setScrollLeft = () => {
if (this.element) {
this.element.scrollLeft = this.containerWidth;
}
};
playerResult = () => {
if (this.data.playOffHoles) {
return (
this.data.playOffHoles.map((item, index) => {
return (
<div
className="leaderboard__player-result-row-wrapper"
key={index}
>
<div className="leaderboard__player-result-row">
<div className="leaderboard__player-result-cell">{item.holeId}</div>
</div>
<div className="leaderboard__player-result-row">
<div className="leaderboard__player-result-cell">{item.holePar}</div>
</div>
<div className="leaderboard__player-result-row">
<div className="leaderboard__player-result-cell leaderboard__player-result-cell--score">
<ScoreCell
childCss='tee-times-card__score'
theme={getScoreTheme(item.playOffParScore)}
>{item.playOffParScore}</ScoreCell>
</div>
</div>
</div>
);
})
);
}
};
render() {
console.log('LeaderboardPlayerResult render');
this.setScrollLeft();
return (
<div
className="leaderboard__player-result"
ref={this.playerResultRef}
>
{this.playerResult()}
</div>
);
}
}
The best place to put this.setScrollLeft() is inside the componentDidUpdate method.
You are already calling this method (this.setScrollLeft()) inside componentDidMount, what is right. Now, you could put another call into componentDidUpdate and it will work pretty much as it is working by now because componentDidUpdate is called before render.
The final outcome will be the same, however, you are separating the concerns: render only render the components and the other methods deal with your business logic.
If you are not sure about componentDidMount and componentDidUpdate, see these excerpts from the official React.js documentation:
componentDidMount()
componentDidMount() is invoked immediately after a component is mounted. Initialization that requires DOM nodes should go here. If you need to load data from a remote endpoint, this is a good place to instantiate the network request. Setting state in this method will trigger a re-rendering.
componentDidUpdate()
componentDidUpdate() is invoked immediately after updating occurs. This method is not called for the initial render.

Why setState re-renders even if state stays the same?

class App extends React.Component {
state = {
index: 0,
}
render() {
alert('rendered');
return(
<div>
<h1>{this.state.index}</h1>
<button onClick={() => this.setState({index: 0})}>test</button>
</div>
);
}
}
I know we can define a shouldComponentUpdate to check if this.state === nextState, but why don't React check this by default? Same goes for props.
React defaults to always re-rendering because then React by default is always correct regardless of what you have in your state.
Iterating the keys of this.state and using === works in your example, but with complex state it's not possible to use simple equality. Take the following example, the indices Array is the same Array so === would return true:
class App extends React.Component {
state = {
indices: [0],
}
render() {
alert('rendered');
return(
<div>
<h1>{this.state.index}</h1>
<button onClick={() => {
this.state.indices.push(2);
this.setState({indices: this.state.indices})
}>test</button>
</div>
);
}
}
State can have Arrays, Objects, etc., and React does not try to infer what "equality" means for them. If you want to optimize your components, you can implement shouldComponentUpdate because you know what "equality" means for your own state.
If you are sure your component's state & props can be compared using simple equality, like in your example, you can extend React.PureComponent to get the behavior you describe.

How to make subchild affect parent state in react

Intro
I'm just beggining with react, but I've got a project and I want to be able to affect parent state from a sub components (or however it's made).
The final result is to get a Contact list that can be edited on the fly.
Problem:
The easiest way to simplify the probably, that I have is probably by starting with the TodoApp (from React's site) that i've modified slightly. Instead of having a list item that is staticly constructed from the state
ParentState ---> Content
I want to be able to have something like this
ParentState <--> ContentInput
State of my problem:
The following code is where i'm stuck at. There is a comment down bellow. I would like to have that imput affect the TodoApp's State. Maybe I got it the wrong way, if so, what is the Right Way?
class TodoApp extends React.Component {
constructor(props) {
super(props);
this.state = { items: [] };
this.handleSubmit = this.handleSubmit.bind(this);
this.showState = this.showState.bind(this);
}
render() {
return (
<div>
<h3>TODO</h3>
<button onClick={this.showState}>Console log current state</button>
<TodoList items={this.state.items} />
<form onSubmit={this.handleSubmit}>
<input ref="field" />
<button>
Add #{this.state.items.length + 1}
</button>
</form>
</div>
);
}
handleSubmit(e) {
e.preventDefault();
if (!this.refs.field.value.length) {
return;
}
const newItem = {
text: this.refs.field.value,
id: Date.now()
};
this.setState(prevState => ({
items: prevState.items.concat(newItem)
}));
}
showState() {
console.log(this.state)
}
}
class TodoList extends React.Component {
render() {
return (
<ul>
{this.props.items.map(item => (
// MAKE THAT INPUT CHANGE THE PARENT STATE
<li key={item.id}><input type="text" defaultValue={item.text} /></li>
))}
</ul>
);
}
}
ReactDOM.render(<TodoApp />, document.getElementById('root'))
https://codepen.io/smdimagerie/pen/Zvdoaj?editors=0010
If you really need direct communication between your parent and something deep in its render tree, you typically have a questionable design going on that should get cut up into single parent-child communication steps, so that you can ask at each step "is it really necessary that this specific child talks to this specific parent?".
That said, the obvious React way to do this is to pass down a function handler so that children can propagate data to a parent, which can then do "whatever is necessary":
class Parent extends Component {
onChange(e) {
...
}
render() {
return <Child onChange={e => this.onChange(e)}/>
}
}
and then make the child call its this.props.onChange(...) when you need it to trigger functionality in the parent. If you need that to happen in the child's children, then you keep passing it down as far as necessary.
Alternatively, if you have a distance to cover, what you probably need instead is for "maybe some component, I don't know which, and I don't care" to do something based on an event getting generated. In this case, you can either use standard JS custom events dispatched on the document, or use a dipatching service like flux (which for small use cases is absurd overkill).

React dumb component with UI state

I want to build a select input component with React.
The select should be dumb component as it's only a UI Component,
but it also have it's own state (Whether to show the options list, or not)
How should I manage this state?
return (
const Select = (props) => {
<div>
<label>{placeholder}</label>
{/*some toggle state*/ && <div>props.children</div>}
</div>
}
)
thanks!
You should not get too confused by the fact that "it's only a UI component". Anything that has an internal state should be a class.
Your code, a dropdown, is my go-to example of when you should use internal state.
Manage your state with setState().
Now your component is stateless, but you need a stateful.
For example:
class Select extends React.Component {
constructor(props) {
super(props);
this.state = {value: '', toggle: false};
}
render() {
return (
<div>
<label>{placeholder}</label>
{this.state.toggle && <div>this.props.children</div>}
</div>
);
}
}
And you should change state with setState function.
For more information, check this article.
According to your code, what you are rendering is a stateless component, so it will not have any state.
What you can do is pass the state from the parent to this component like so:
constructor(props) {
this.state = { showDumbComponent:true }
}
render() {
<DumbComponent show={this.state.showDumbComponent} />
}

ReactJS Curry Functions to delay Event Binding

I am new with React(way) of building UIs and also dabbling with FP a little bit.
Basically , I wanted to know if using curried Functions to delay binding events with fields is a good practice and are there any performance implications.
For EG:
I have a set of Posts and for Each Post there is a Comment Box, where users can comment on that POST.So we will need the Post and the relevent Comment for that Post in my Event Hanlder which is just a function.
Check the working code example at CodePen :
Event Binding
/*
* A simple React component
*/
class Application extends React.Component {
constructor(props){
super(props)
console.log(props)
this.state = {
posts:['post1', 'post2', 'post3']
}
}
render() {
return (
<div>
<ul>
{ this.state.posts.map(
(post, i) => {
return (
<PostSingle post = {post} index = {i} bindPost = {this.props.post(post)}/>
)
}
) }
</ul>
</div>
)
}
}
const PostSingle = ({post, index,bindPost}) => {
let handlePostComment = () => {
return bindPost(null)
}
return (
<div>
<li key={index}>
<input onChange = {
(e) => {
let value = e.target.value
handlePostComment = () => {
return bindPost(value)
}
}
}></input>
<button onClick={() => {handlePostComment()}}>Comment</button>
<p key={index}>{post}</p>
</li>
</div>
)
}
/*
* Render the above component into the div#app
*/
const PostComment = post => comment => {
alert(`You commented ${comment} for ${post}`)
}
ReactDOM.render(<Application post={PostComment}/>, document.getElementById('app'));
So basically PostComment function gets properties in a curried fashion as an when the Objects gets created.
i could not find much examples of these except in Redux Tutorials.
In Actual application the events can be passed to the main component using props in mapDispatchToProps() using Redux.
Your thoughts and comments would be much appreciated.
I think using post property and state is a much more Reacty way. handlePostComment will be reinitialized on every render call so this code is more imperative then functional (IMHO using closures does not make the code functional).
State is the React way of handling imperative logic and you can benefit from React optimizations by using state and props properly.
Generally I think it breaks React Redux philosophy of having a single source of truth.
Also you can't make your input controlled by providing a value in this case.

Resources