create account

Busy Contribution Report #2: Understanding React & Redux to Improve "Interesting People" by ryanbaer

View this thread on: hive.blogpeakd.comecency.com
· @ryanbaer · (edited)
$24.35
Busy Contribution Report #2: Understanding React & Redux to Improve "Interesting People"
![BusyContrib.png](https://res.cloudinary.com/hpiynhbhq/image/upload/v1509088185/mgyugnupu46bxsaybj2b.png)

---
# Busy Contribution Report #2: Understanding React & Redux to Improve "Interesting People"
### What is "Interesting People"?
![image.png](https://res.cloudinary.com/hpiynhbhq/image/upload/v1508876609/lspng9enurxtpsakwvru.png)

One of the features that I first noticed in Busy's new design was a handy little pane in the sidebar labeled "Interesting People".

This feature exemplifies how Busy continues to enhance the UX (User Experience) of interacting with the Steem blockchain.

As you browse through Busy, the Interesting People pane populates with a list of users. These are users that tend to post interesting / unique content on Steemit whom you may be interested in following.

Furthermore, should you want to cycle through and see other suggestions, there's a refresh button on the pane that fetches another 5 suggestions for you.

### What's the issue?
![image.png](https://res.cloudinary.com/hpiynhbhq/image/upload/v1508876274/yhob9mkuvtglx6xptl0i.png)

Last week, @espoem reported an issue having to do with this feature:
[Already followed user appears among Interesting People after (re)loading the page](https://github.com/busyorg/busy/issues/810)

As he points out, he often saw that, upon browsing to a different page, users would appear in the list that he's already following.

At the outset, it doesn't seem too horrible to see someone you've already followed in there. But if you think about it, over time, the majority of your recommendations could contain users you follow, which reduces the usefulness of the feature.

What we want is to always only have users in there that the user hasn't yet followed.

## What's the fix?

![image.png](https://res.cloudinary.com/hpiynhbhq/image/upload/v1508881024/ztnnk6rgjeursbixzm4g.png)

The fix, as usual, I go into in more detail in the Technical Details section. But for those of you not interested in that, it's very simple on the surface. The feature now only delivers you fresh suggestions based on who you're currently following. If you followed someone from the recommendations and then browsed to another page, that user is not going to appear in the list.

For those of your who are more technical and are interested in learning a bit about React and Redux, I've written the section to be somewhat educational as well, so my hope is that it can be useful to you if you're new to the topics.

## Verification
For verification, here is my PR: 
[Fix for #810: followed user appears among recs after reloading the page](https://github.com/busyorg/busy/pull/893)

## Technical Details
![giphy (2).gif](https://res.cloudinary.com/hpiynhbhq/image/upload/v1508880840/nb2wq1xce1gshyf8dhbx.gif)

### Context
Some important context to note here is the libraries on which the Busy app is built. The app is developed using React and Redux, among others. For web developers who haven't used them before and are more familiar with libraries like Angular or Ember, it's a bit of a paradigm shift. This write-up obviously won't be a full-blown tutorial on React or Redux, but you should be able to follow along, and may want to do a quick Google if you get a little lost. Also, I'm happy to make myself available in the comments if you have questions.

### Root Cause Analysis
The term "root cause analysis" is simply a fancy way to describe the process of getting to the root of the problem. In this case, the problem is that users are showing up in the Interesting People list that the user is already following.

To find the root cause, first we need to locate the code that is generating the list. I don't remember exactly where I started, but after a search or two of the code base, I found that the list gets rendered in our `RightSidebar` component. Naturally, this is the sidebar that appears on the right hand side of the screen in Busy.

Looking into the component, I found that, in its constructor, we call the method `getRandomPeople` which generates the list of Interesting People.

Digging into `getRandomPeople`, I saw that it accesses the component's props to get the list of users followed by the current user. It then filters any users in that list out of the Interesting People recommendations and returns 5 random people that the user hasn't yet followed.

So the logic in the function itself seems perfectly straightforward - take all the Interesting People and remove anyone who the user is already following. But there's actually something wrong with our data flow, if you haven't noticed already.

How do we get the list of users that the current user is following? Well, that involves a network request, and in our application, that involves dispatching an action which asynchronously makes the request. Upon a successful fetch of the user's following list, the action `@user/GET_FOLLOWING` is dispatched containing the list as its payload.

OK, that seems fine, but the issue comes into play with the assumption that the user's following list has already been retrieved at the time that the `RightSidebar` is instantiated (i.e. its constructor method runs).

Since we're working with React components, we need to be aware of the [React lifecycle](https://reactjs.org/docs/react-component.html#the-component-lifecycle).

![image.png](https://res.cloudinary.com/hpiynhbhq/image/upload/v1508877183/w4chmxf5vnmqy6hsugnb.png)

Looking in the docs, we find the following:

> #### The Component Lifecycle
> Each component has several “lifecycle methods” that you can override to run code at particular times in the process. Methods prefixed with will are called right before something happens, and methods prefixed with did are called right after something happens.
> #### Mounting
> These methods are called when an instance of a component is being created and inserted into the DOM:
constructor()
componentWillMount()
render()
componentDidMount()

Looking into the documentation for the constructor, we see a few interesting things:
> The constructor for a React component is called before it is mounted.
> ...
> Avoid introducing any side-effects or subscriptions in the constructor. For those use cases, use componentDidMount() instead.

And that confirms the issue - at the time the constructor for our `RightSidebar` component runs, the component hasn't even been mounted yet. This means that it's unlikely the network request would have had time to be fulfilled at the time the constructor runs.

But to confirm that the sequence is off here, let's trace the code of when we dispatch the request to get the user's following list. A quick few searches on Github yielded the following:
- We dispatch the `getFollowing` action from within `login` action.
- The `login` action is dispatched by the `Wrapper` component, specifically within the `Wrapper` component's `componentDidMount` method.
- The `Wrapper` component is a special component that is one of the first things to run when our app loads

In writing this post, I became curious of when a child component's constructor actually runs relative to its parent's lifecycle methods. Is there just a chain of constructors running recursively until all components are instantiated? That seems like it wouldn't be a very performant approach. So I did a little experiment with some `console.log` statements just to get an idea, and it appears that:
- When the parent's `render` method runs, the child's `constructor` runs, i.e. the child is instantiated.
- The child component has to mount (componentDidMount) before the parent successfully mounts

I don't know the specific average timing of how long it takes a React component to mount versus how long it takes the Redux action to get dispatched and the network request to return. But I think it's safe to say that it's incredibly unlikely that the network request will return with the list in anywhere near the amount of time that it takes for all of `RightSidebar`'s ancestor components to render.

So ultimately, the root cause is a sequencing issue. By the time the `@user/GET_FOLLOWING_SUCCESS` action returns with the list of followed users, the constructor method of the `RightSidebar` has already run quite a while beforehand.

### The Fix
![fix.gif](http://res.cloudinary.com/hpiynhbhq/image/upload/v1508876899/yk3jrkmdqakkqtwvtybm.gif)

My approach to the fix of this issue is best described in my Pull Request description:
> This is a fix for the issue that caused previously followed users to appear in new recommendations for Interesting People.
> 
> The issue had to do with React lifecycle. getRandomPeople was being called from within the constructor of the component, quite a while before `@user/GET_FOLLOWING_SUCCESS` returns with the list of the user's current followers. As a result, on page load, getRandomPeople always received an empty array of followers and hence did not filter any users out.
> 
> My approach to the solution was to pull the local state out of the component and into the Redux state tree. This way, RightSidebar no longer has to deal with the follower list directly, and the logic for generating the recommendations is handled in the reducer. Any components making use of the interesting people list don't have to be concerned with how it's generated.
> 
> This approach also allows us to update that list in response to other events, should we want to. For example, I had a small implementation going where, if the user followed someone (`@user/FOLLOW_USER_SUCCESS`) that was in the list, it would:
> 
> - Remove that person from the Interesting People list
> - Keep the remaining 4 people in the list
> - Populate the empty slot with another random person
> It was a quick implementation that I decided to leave out since it diverges from the original behavior of being able to click unfollow after you've clicked follow, but I think it's a good example of what else could be done.
> 
> Thanks.



## Hey, I'm Ryan.

<center>[![MeIceBath.png](https://res.cloudinary.com/hpiynhbhq/image/upload/v1508620872/jttny7hmtlhkhnlequlf.png)](https://steemit.com/introduce/@ryanbaer/hi-steemit-i-m-ryan-software-engineer-hypnotist-and-futurism-enthusiast)</center>


I'm a software engineer living in the Bay Area who was introduced to Steemit about a year ago and recently started posting again. You can learn more about me in my [intro post](https://steemit.com/introduce/@ryanbaer/hi-steemit-i-m-ryan-software-engineer-hypnotist-and-futurism-enthusiast).

---

## References
### Research
- [React Documentation](https://reactjs.org/docs/react-component.html)

### Images
- Title Image: Utopian Logo, Steem Logo, Busy Logo
- Giphy
- [MuseFind Engineering](https://engineering.musefind.com/react-lifecycle-methods-how-and-when-to-use-them-2111a1b692b1)


<br /><hr/><em>Open Source Contribution posted via https://utopian.io</em><hr/>
👍  , , , , , , , , , , , , , , , ,
properties (23)
authorryanbaer
permlinkbusy-contribution-report-2-understanding-react-and-redux-to-improve-interesting-people
categoryutopian-io
json_metadata{"community":"busy","app":"busy/2.0.0","format":"markdown","tags":["utopian-io","busy","steemdev","programming","opensource"],"users":["espoem","user","ryanbaer"],"links":["https://github.com/busyorg/busy/issues/810","https://github.com/busyorg/busy/pull/893","https://reactjs.org/docs/react-component.html#the-component-lifecycle","https://steemit.com/introduce/@ryanbaer/hi-steemit-i-m-ryan-software-engineer-hypnotist-and-futurism-enthusiast","https://steemit.com/introduce/@ryanbaer/hi-steemit-i-m-ryan-software-engineer-hypnotist-and-futurism-enthusiast","https://reactjs.org/docs/react-component.html","https://engineering.musefind.com/react-lifecycle-methods-how-and-when-to-use-them-2111a1b692b1","https://utopian.io"],"image":["https://res.cloudinary.com/hpiynhbhq/image/upload/v1509088185/mgyugnupu46bxsaybj2b.png","https://res.cloudinary.com/hpiynhbhq/image/upload/v1508876609/lspng9enurxtpsakwvru.png","https://res.cloudinary.com/hpiynhbhq/image/upload/v1508876274/yhob9mkuvtglx6xptl0i.png","https://res.cloudinary.com/hpiynhbhq/image/upload/v1508881024/ztnnk6rgjeursbixzm4g.png","https://res.cloudinary.com/hpiynhbhq/image/upload/v1508880840/nb2wq1xce1gshyf8dhbx.gif","https://res.cloudinary.com/hpiynhbhq/image/upload/v1508877183/w4chmxf5vnmqy6hsugnb.png","http://res.cloudinary.com/hpiynhbhq/image/upload/v1508876899/yk3jrkmdqakkqtwvtybm.gif","https://res.cloudinary.com/hpiynhbhq/image/upload/v1508620872/jttny7hmtlhkhnlequlf.png"]}
created2017-10-24 22:05:54
last_update2017-10-27 07:12:15
depth0
children6
last_payout2017-10-31 22:05:54
cashout_time1969-12-31 23:59:59
total_payout_value17.303 HBD
curator_payout_value7.046 HBD
pending_payout_value0.000 HBD
promoted0.000 HBD
body_length10,862
author_reputation4,435,202,574,651
root_title"Busy Contribution Report #2: Understanding React & Redux to Improve "Interesting People""
beneficiaries
0.
accountcryptoctopus
weight181
1.
accountelear
weight255
2.
accountfreedom
weight878
3.
accountfurion
weight40
4.
accountjavybar
weight36
5.
accountjohnsmith
weight145
6.
accounttransisto
weight471
7.
accountxeldal
weight146
max_accepted_payout1,000,000.000 HBD
percent_hbd0
post_id18,484,548
net_rshares12,911,563,215,617
author_curate_reward""
vote details (17)
@adikuala ·
Hey @ryanbae How are you today?
I am @adikuala I love developers.
You write more than the average for this category. Good work! -You use more images than the average for this category. Big
You have a good amount of votes for your contribution.
Good work Up-vote this comment to grow my strength and help Open Source contribution like this.
my best regards @adikuala

Aim.
I am @adikuala want and feel interested to post on the page @ utopian-io as well as your post @ryanbae
I want your more concise guidance that you specifically send to my email @ adikuala in my email user name click here.adikuala9@gmail.com

my hope @adikuala to @ryanbae
voluntarily you teach me how to post a good one at @ utopian.io.
from the first step to the end of a post at @ utopian.io I will be very grateful to you and I promise to teach it to other pomula-pomula. so it can create power in open source contributions as I've mentioned above.

thanks.
my best regards @adikuala
from the city of North Aceh
Indonesia
properties (22)
authoradikuala
permlinkre-ryanbaer-busy-contribution-report-2-understanding-react-and-redux-to-improve-interesting-people-20180202t064922566z
categoryutopian-io
json_metadata{"tags":["utopian-io"],"community":"utopian","app":"utopian/1.0.0"}
created2018-02-02 06:49:03
last_update2018-02-02 06:49:03
depth1
children0
last_payout2018-02-09 06:49:03
cashout_time1969-12-31 23:59:59
total_payout_value0.000 HBD
curator_payout_value0.000 HBD
pending_payout_value0.000 HBD
promoted0.000 HBD
body_length995
author_reputation669,670,106,987
root_title"Busy Contribution Report #2: Understanding React & Redux to Improve "Interesting People""
beneficiaries[]
max_accepted_payout1,000,000.000 HBD
percent_hbd10,000
post_id34,327,767
net_rshares0
@drigweeu ·
Approved: great development @ryanbaer
properties (22)
authordrigweeu
permlinkre-ryanbaer-busy-contribution-report-2-understanding-react-and-redux-to-improve-interesting-people-20171024t222109479z
categoryutopian-io
json_metadata{"tags":["utopian-io"],"community":"utopian","app":"utopian/1.0.0"}
created2017-10-24 22:21:33
last_update2017-10-24 22:21:33
depth1
children0
last_payout2017-10-31 22:21:33
cashout_time1969-12-31 23:59:59
total_payout_value0.000 HBD
curator_payout_value0.000 HBD
pending_payout_value0.000 HBD
promoted0.000 HBD
body_length37
author_reputation10,306,722,602,236
root_title"Busy Contribution Report #2: Understanding React & Redux to Improve "Interesting People""
beneficiaries[]
max_accepted_payout1,000,000.000 HBD
percent_hbd10,000
post_id18,485,220
net_rshares0
@eastmael ·
Thank you for this tutorial and the great explanation regarding the React lifecycle . 
properties (22)
authoreastmael
permlinkre-ryanbaer-busy-contribution-report-2-understanding-react-and-redux-to-improve-interesting-people-20171025t034609202z
categoryutopian-io
json_metadata{"tags":["utopian-io"],"community":"utopian","app":"utopian/1.0.0"}
created2017-10-25 03:46:18
last_update2017-10-25 03:46:18
depth1
children0
last_payout2017-11-01 03:46:18
cashout_time1969-12-31 23:59:59
total_payout_value0.000 HBD
curator_payout_value0.000 HBD
pending_payout_value0.000 HBD
promoted0.000 HBD
body_length86
author_reputation78,967,407,130,763
root_title"Busy Contribution Report #2: Understanding React & Redux to Improve "Interesting People""
beneficiaries[]
max_accepted_payout1,000,000.000 HBD
percent_hbd10,000
post_id18,499,709
net_rshares0
@stoodkev ·
Great contribution, the new version of Busy will rock! Post accepted on Utopian of course =)
properties (22)
authorstoodkev
permlinkre-ryanbaer-busy-contribution-report-2-understanding-react-and-redux-to-improve-interesting-people-20171024t222128359z
categoryutopian-io
json_metadata{"tags":["utopian-io"],"community":"utopian","app":"utopian/1.0.0"}
created2017-10-24 22:21:30
last_update2017-10-24 22:21:30
depth1
children1
last_payout2017-10-31 22:21:30
cashout_time1969-12-31 23:59:59
total_payout_value0.000 HBD
curator_payout_value0.000 HBD
pending_payout_value0.000 HBD
promoted0.000 HBD
body_length92
author_reputation190,283,772,273,558
root_title"Busy Contribution Report #2: Understanding React & Redux to Improve "Interesting People""
beneficiaries[]
max_accepted_payout1,000,000.000 HBD
percent_hbd10,000
post_id18,485,213
net_rshares0
@ryanbaer ·
Thanks!
properties (22)
authorryanbaer
permlinkre-stoodkev-re-ryanbaer-busy-contribution-report-2-understanding-react-and-redux-to-improve-interesting-people-20171026t033928499z
categoryutopian-io
json_metadata{"tags":["utopian-io"],"community":"busy","app":"busy/2.0.0"}
created2017-10-26 03:39:27
last_update2017-10-26 03:39:27
depth2
children0
last_payout2017-11-02 03:39:27
cashout_time1969-12-31 23:59:59
total_payout_value0.000 HBD
curator_payout_value0.000 HBD
pending_payout_value0.000 HBD
promoted0.000 HBD
body_length7
author_reputation4,435,202,574,651
root_title"Busy Contribution Report #2: Understanding React & Redux to Improve "Interesting People""
beneficiaries[]
max_accepted_payout1,000,000.000 HBD
percent_hbd10,000
post_id18,582,072
net_rshares0
@utopian-io ·
$0.08
### Hey @ryanbaer I am @utopian-io. I have just super-voted you at 78% Power!
#### Achievements
-I am a bot...I love developers... <3
-You are writing more than the average for this category. Good job!
-You are using more images than the average for this category. Great!
-You have a good amount of votes on your contributions. Good job!
**Up-vote this comment to grow my power and help Open Source contributions like this one.**
👍  , ,
properties (23)
authorutopian-io
permlinkre-ryanbaer-busy-contribution-report-2-understanding-react-and-redux-to-improve-interesting-people-20171025t000206235z
categoryutopian-io
json_metadata{"tags":["utopian-io"],"community":"utopian","app":"utopian/1.0.0"}
created2017-10-25 00:02:06
last_update2017-10-25 00:02:06
depth1
children0
last_payout2017-11-01 00:02:06
cashout_time1969-12-31 23:59:59
total_payout_value0.072 HBD
curator_payout_value0.006 HBD
pending_payout_value0.000 HBD
promoted0.000 HBD
body_length429
author_reputation152,955,367,999,756
root_title"Busy Contribution Report #2: Understanding React & Redux to Improve "Interesting People""
beneficiaries[]
max_accepted_payout1,000,000.000 HBD
percent_hbd10,000
post_id18,489,609
net_rshares36,060,252,825
author_curate_reward""
vote details (3)