As you might remember from the Redux-based Pokedex project, implementing Redux results in a lot of boilerplate code. Using Redux hooks can help clean up and get rid of a lot of boilerplate code. In this phase you will refactor the Redux-based project to use React hooks and implement Redux hooks!
In this phase, you’ll be refactoring all your component files to use Redux
hooks instead of the mapStateToProps
,
mapDispatchToProps
, and Redux connect
functions.
Just like in phase 1, you might hit bugs and break your application while
refactoring your application’s components. Make sure to test that your
refactored code is working before moving on to refactor the next
component. As a general overview, you’ll be refactoring the code for the
following components:
LogoutButton
LoginPanel
PokemonDetail
PokemonForm
PokemonBrowser
useDispatch
and useSelector
You’ll need to do some refactoring so that your component doesn’t receive
any props. Instead of receiving slices of state and dispatchable action
functions as props from the connect
wrapper, you will use the
useSelector
hook to access a slice a state from within the
component and the useDispatch
hook to dispatch actions from
within the component.
Take a look at the LogoutButton
component as an example.
Based on the mapStateToProps
and
mapDispatchToProps
functions in the
LogoutButton.js
file, you can tell that the component is
accessing Redux by receiving loggedOut
and
logout
props.
// We'll convert this into a useSelector hook
const mapStateToProps = (state) => {
return {
loggedOut: !state.authentication.token,
};
};
// We'll convert this into a useDispatch hook
const mapDispatchToProps = (dispatch) => {
return {
logout: () => dispatch(logout()),
};
};
export default connect(mapStateToProps, mapDispatchToProps)(LogoutButton);
Take a moment to import the useSelector
and
useDispatch
from the Redux library into the file.
Now you’ll use Redux hooks within the LoginButton
component
so that you can remove the mapStateToProps
,
mapDispatchToProps
, and connect
functions!
mapStateToProps
to useSelector
Instead of receiving a loggedOut
prop, you’ll use the
useSelector
hook to access the state’s
authentication.token
.
Add the useSelector
to the top of your component.
const LogoutButton = () => {
const loggedOut = useSelector((state) => !state.authentication.token);
// CODE SHORTENED FOR BREVITY
};
Feel free to visit the Redux Hooks documentation to view [
useSelector
> examples].
Then inside the component you can convert the
props.loggedOut
to simply use the new variable
loggedOut
const LogoutButton = () => {
const loggedOut = useSelector((state) => !state.authentication.token);
if (loggedOut) {
return <Redirect to="/login" />;
}
return (
<div id="logout-button-holder">
<button onClick={handleClick}>Logout</button>
</div>
);
};
mapDispatchToProps
to useDispatch
Notice how the logout
thunk action creator function has
already been imported into your LogoutButton.js
file. You’ll
use useDispatch
hook to return a reference to the
dispatch
function from the Redux store:
Then you can use the dispatch
function to dispatch the
logout
function directly inside the
handleClick
function instead of doing it in
mapDispatchToProps
.
So much simpler!
const LogoutButton = () => {
const loggedOut = useSelector((state) => !state.authentication.token);
const dispatch = useDispatch();
const handleClick = () => dispatch(logout());
// CODE SHORTENED FOR BREVITY
};
Feel free to visit the Redux Hooks documentation to view [
useDispatch
> examples].
mapStateToProps
, mapDispatchToProps
,
and connect
Now that we aren’t referencing props.logout
and
props.loggedOut
, you can remove all the old Redux boilerplate
code.
Lastly, you’ll want to remove the mapStateToProps
and
mapDispatchToProps
functions from the file, and replace the
connect
function to an export statement that exports the
LoginButton
component by default:
Now that you’ve gone over how to refactor your
LogoutButton
component, follow the same pattern to implement
Redux hooks into your LoginPanel
, PokemonDetail
,
PokemonForm
, and PokemonBrowser
components.
useParams
Notice the references to the React Router match
prop accessed
in your PokemonBrowser
and
PokemonDetail
components? Instead of having your component
take in a match
prop to access the route parameters, you’ll
implement the useParams
prop and use object destructuring to
access the pokemonId
parameter in the
PokemonBrowser
component and the id
parameter in
the PokemonDetail
component. Feel free to visit React Router
documentation to view examples of using the
useParams
hook.
Once you have finished refactoring, take a moment to commit your changes:
As you can see, refactoring to Functional components with Hooks makes your code much smaller and easier to understand! Going forward with your coding career you’ll probably want to always use hooks instead of class based components, but it’s good that you know how to read class based components and you’ll be able to refactor class based component code to functional hooks components whereever you find them!
Context
Now that you have practiced refactoring your application to implement
Redux hooks, it’s time to work on a Context-based project utilizing
React’s useContext
hook! However we can’t very well do this
in our Redux project since it uses Redux to store all of the state instead
of Context
! So we’ll be starting with an alternative Pokedex
project which uses Context
instead.


Class: OpenTok::Archive
- Inherits:
-
Object
- Object
- OpenTok::Archive
- Defined in:
- lib/opentok/archive.rb
Overview
Represents an archive of an OpenTok session.
Instance Attribute Summary (collapse)
-
- (int) created_at
The time at which the archive was created, in milliseconds since the UNIX epoch.
-
- (string) duration
The duration of the archive, in milliseconds.
-
- (true, false) has_audio
Whether the archive has an audio track (true) or not (false).
-
- (true, false) has_video
Whether the archive has a video track (true) or not (false).
-
- (string) id
The archive ID.
-
- (string) name
The name of the archive.
-
- (String) output_mode
Whether all streams in the archive are recorded to a single file (:composed) or to individual files (:individual).
-
- (string) partner_id
The API key associated with the archive.
-
- (string) reason
For archives with the status "stopped", this can be set to "90 mins exceeded", "failure", "session ended", or "user initiated".
-
- (string) session_id
The session ID of the OpenTok session associated with this archive.
-
- (float) size
The size of the MP4 file.
-
- (string) status
The status of the archive, which can be one of the following:.
-
- (string) url
The download URL of the available MP4 file.
Instance Method Summary (collapse)
-
- (Object) delete
Deletes an OpenTok archive.
-
- (Object) stop
Stops an OpenTok archive that is being recorded.
-
- (Object) to_json
A JSON encoded string representation of the archive.
Dynamic Method Handling
This class handles dynamic methods through the method_missing method
- (Object) method_missing(method, *args, &block)
100 101 102 103 104 105 106 107 108 109 110 111 112 |
# File 'lib/opentok/archive.rb', line 100 def method_missing(method, *args, &block) camelized_method = method.to_s.camelize(:lower) if @json.has_key? camelized_method and args.empty? # TODO: convert create_time method call to a Time object if camelized_method == 'outputMode' @json[camelized_method].to_sym else @json[camelized_method] end else super method, *args, &block end end |
Instance Attribute Details
- (int) created_at
The time at which the archive was created, in milliseconds since the UNIX epoch.
66 67 68 |
# File 'lib/opentok/archive.rb', line 66 def created_at @created_at end |
- (string) duration
The duration of the archive, in milliseconds.
66 67 68 |
# File 'lib/opentok/archive.rb', line 66 def duration @duration end |
- (true, false) has_audio
Whether the archive has an audio track (true) or not (false).
66 67 68 |
# File 'lib/opentok/archive.rb', line 66 def has_audio @has_audio end |
- (true, false) has_video
Whether the archive has a video track (true) or not (false).
66 67 68 |
# File 'lib/opentok/archive.rb', line 66 def has_video @has_video end |
- (string) id
The archive ID.
66 67 68 |
# File 'lib/opentok/archive.rb', line 66 def id @id end |
- (string) name
The name of the archive. If no name was provided when the archive was created, this is set to null.
66 67 68 |
# File 'lib/opentok/archive.rb', line 66 def name @name end |
- (String) output_mode
Whether all streams in the archive are recorded to a single file (:composed) or to individual files (:individual).
66 67 68 |
# File 'lib/opentok/archive.rb', line 66 def output_mode @output_mode end |
- (string) partner_id
The API key associated with the archive.
66 67 68 |
# File 'lib/opentok/archive.rb', line 66 def partner_id @partner_id end |
- (string) reason
For archives with the status "stopped", this can be set to "90 mins exceeded", "failure", "session ended", or "user initiated". For archives with the status "failed", this can be set to "system failure".
66 67 68 |
# File 'lib/opentok/archive.rb', line 66 def reason @reason end |
- (string) session_id
The session ID of the OpenTok session associated with this archive.
66 67 68 |
# File 'lib/opentok/archive.rb', line 66 def session_id @session_id end |
- (float) size
The size of the MP4 file. For archives that have not been generated, this value is set to 0.
66 67 68 |
# File 'lib/opentok/archive.rb', line 66 def size @size end |
- (string) status
The status of the archive, which can be one of the following:
-
"available" -- The archive is available for download from the OpenTok cloud.
-
"expired" -- The archive is no longer available for download from the OpenTok cloud.
-
"failed" -- The archive recording failed.
-
"paused" -- The archive is in progress and no clients are publishing streams to the session. When an archive is in progress and any client publishes a stream, the status is "started". When an archive is paused, nothing is recorded. When a client starts publishing a stream, the recording starts (or resumes). If all clients disconnect from a session that is being archived, the status changes to "paused", and after 60 seconds the archive recording stops (and the status changes to "stopped").
-
"started" -- The archive started and is in the process of being recorded.
-
"stopped" -- The archive stopped recording.
-
"uploaded" -- The archive is available for download from the the upload target Amazon S3 bucket or Windows Azure container you set at the OpenTok dashboard (dashboard.tokbox.com).
66 67 68 |
# File 'lib/opentok/archive.rb', line 66 def status @status end |
- (string) url
The download URL of the available MP4 file. This is only set for an archive with the status set to "available"; for other archives, (including archives with the status "uploaded") this property is set to null. The download URL is obfuscated, and the file is only available from the URL for 10 minutes. To generate a new URL, call the Archive.listArchives() or OpenTok.getArchive() method.
66 67 68 |
# File 'lib/opentok/archive.rb', line 66 def url @url end |
Instance Method Details
- (Object) delete
Deletes an OpenTok archive.
You can only delete an archive which has a status of "available" or "uploaded". Deleting an archive removes its record from the list of archives. For an "available" archive, it also removes the archive file, making it unavailable for download.
94 95 96 97 |
# File 'lib/opentok/archive.rb', line 94 def delete # TODO: validate returned json fits schema @json = @interface.delete_by_id @json['id'] end |
- (Object) stop
Stops an OpenTok archive that is being recorded.
Archives automatically stop recording after 90 minutes or when all clients have disconnected from the session being archived.
84 85 86 87 |
# File 'lib/opentok/archive.rb', line 84 def stop # TODO: validate returned json fits schema @json = @interface.stop_by_id @json['id'] end |
- (Object) to_json
A JSON encoded string representation of the archive
76 77 78 |
# File 'lib/opentok/archive.rb', line 76 def to_json @json.to_json end |


oo::util - Utility commands for TclOO
This package provides a convenience command for the easy specification of instance methods as callback commands, like timers, file events, Tk bindings, etc.
This command is available within instance methods. It takes a method name and, possibly, arguments for the method and returns a command prefix which, when executed, will invoke the named method of the object we are in, with the provided arguments, and any others supplied at the time of actual invokation.
Note: The command is equivalent to and named after the command provided by the OO package snit for the same purpose.
This command is available within class definitions. It takes a method name and, possibly, arguments for the method and creates a method on the class, available to a user of the class and of derived classes.
Note: The command is equivalent to the command typemethod provided by the OO package snit for the same purpose.
Example
oo::class create ActiveRecord { classmethod find args { puts "[self] called with arguments: $args" } } oo::class create Table { superclass ActiveRecord } puts [Table find foo bar] # ====== # which will write # ====== # ::Table called with arguments: foo bar
This command is available within instance methods. It takes a series of variable names and makes them available in the method's scope. The originating scope for the variables is the class (instance) the object instance belongs to. In other words, the referenced variables are shared between all instances of their class.
Note: The command is roughly equivalent to the command typevariable provided by the OO package snit for the same purpose. The difference is that it cannot be used in the class definition itself.
Example:
% oo::class create Foo { method bar {z} { classvariable x y return [incr x $z],[incr y] } } ::Foo % Foo create a ::a % Foo create b ::b % a bar 2 2,1 % a bar 3 5,2 % b bar 7 12,3 % b bar -1 11,4 % a bar 0 11,5
This command is available within instance methods. It takes a list of method names and/or pairs of alias- and method-name and makes the named methods available to all instance methods without requiring the my command.
The alias name under which the method becomes available defaults to the method name, except where explicitly specified through an alias/method pair.
Examples:
link foo # The method foo is now directly accessible as foo instead of my foo. link {bar foo} # The method foo is now directly accessible as bar. link a b c # The methods a, b, and c all become directly acessible under their # own names.
The main use of this command is expected to be in instance constructors, for convenience, or to set up some methods for use in a mini DSL.
This command is a meta-class, i.e. a variant of the builtin oo::class which ensures that it creates only a single instance of the classes defined with it.
Syntax and results are like for oo::class.
Example:
% oo::class create example { self mixin singleton method foo {} {self} } ::example % [example new] foo ::oo::Obj22 % [example new] foo ::oo::Obj22
Donal Fellows, Andreas Kupries
This document, and the package it describes, will undoubtedly contain bugs and other problems. Please report such in the category oo::util of the Tcllib Trackers. Please also report any ideas for enhancements you may have for either package and/or documentation.
When proposing code changes, please provide unified diffs, i.e the output of diff -u.
Note further that attachments are strongly preferred over inlined patches. Attachments can be made by going to the Edit form of the ticket immediately after its creation, and then using the left-most button in the secondary navigation bar.
TclOO, callback, class methods, class variables, command prefix, currying, method reference, my method, singleton
Utility
Copyright © 2011-2015 Andreas Kupries, BSD licensed