Render Props Tutorial
Challenge 1: Alternate Uses
Let's use our <Tabs>
component to do something else. We've named it "Tabs", but really it's only doing two things:
- Giving us a number
- And a way to update that number
We can use this for much more than just rendering tabs (We'll cover that in the next challenge). In Sonnet.js
, finish writing the <Sonnet>
component to display only words of a certain length. It should look something like this when you are done:
Notes:
- Don't worry about how punctuation marks are included in the word length.
- Try to do this by working only within the
<Sonnet>
component. (Feel free to break this into other files or components)
Challenge 2: Refactor
We've found that we can use our <Tabs>
component to do things other than rendering tabs. Also, we need to supply it with a location
, history
, and initialTab
prop manually every time we use it. Let's make it all simpler and more flexible.
Steps:
- Rename the
<Tabs>
component, theinitialTab
prop andcurrentTab
,switchTab
render props to something that makes more sense. (I'm going to keep referring to them as 'tabs' in these instructions) - Wrap the default export with
withRouter()
(see the comments in Tabs.js) - Now that we don't need to supply this component with route info manually, remove the wrapping
<Route>
components that give it thelocation
,history
, andinitialTab
props. (In Homepage.js and Sonnet.js) - Have the
<Tabs>
component determine the initial tab on its own, based on the location prop.- Hint: either handle this in the constructor, or make a function that you can pass some props to, i.e.
this.state = { currentTab: getCurrentTab(this.props) || 0 }
- Hint: either handle this in the constructor, or make a function that you can pass some props to, i.e.
- Add
increase
anddecrease
methods and provide them with the render props. - Now that we have a simpler API, go back and change the implementation of
<Sonnet>
Test that you can still switch tabs between each step!!
Challenge 3: React Router Parameters and working with an API
Now that we have this working for one sonnet, let's make this a little more dynamic. First, read up on how to use URL parameters with React Router.
Next:
- Change the
/sonnet
route to/sonnets
, and have make a new component to display a list of sonnet titles.
- Fetch these titles at
https://sonnets-api.now.sh/api/sonnets/toc
- Have each of these titles render a
<Link>
to/sonnet/[sonnet-number]
, where N is the number of that sonnet
- Create a new route:
/sonnet/:number
. Using the URL param from react router, fetch and display that sonnet.
-
HINT: Your routes in App.js will look something like this:
<Switch> <Route path="/" exact component={Homepage} /> <Route path="/sonnets" exact component={SonnetList} /> <Route path="/sonnet/:number" exact component={Sonnet} /> </Switch>
- Modify your
<Sonnet>
component to display sonnets dynamically.
- React Router will give your Sonnect component a
match
prop. Take a look atmatch.params
in the console to see how to get the number that is provided in the URL. - Fetch the sonnet at the endpoint
https://sonnets-api.now.sh/api/sonnets/{number}
(the code for this API is at https://www.github.com/good-idea/sonnet-api in case you want to take a look at a simple express app!)
Stretch Goals
- When determining the length of a word in the
<Sonnet>
component, do not count punctuation marks. - Give a
min
andmax
prop to your (renamed!)<Tabs>
component and ensure that the (renamed!)currentTab
does not exceed them. - Implement a 'Not Found' view
- Show a 'There is no sonnet with this number' view if someone goes to a sonnet page with a number that doesn't correspond with a sonnet.