|
| 1 | +# 15 Context |
| 2 | + |
| 3 | +In this sample we are going to learn how React 16 context api works. |
| 4 | + |
| 5 | +This will allow us to share information between components without having to go through props drilldown or having to add redux support to our project. |
| 6 | + |
| 7 | +We will take a startup point sample 15 Context: |
| 8 | + |
| 9 | +## Steps |
| 10 | + |
| 11 | +- We want to store just the _login_ field once the user logs in and display it in the page B (or in wathever page or component we need it), let's add a default value ('no user'). |
| 12 | + |
| 13 | +- Let's start by creating a context, we will call it _sessionContext_, and add the proper typing |
| 14 | + |
| 15 | +_./src/common/sessionContext.tsx_ |
| 16 | + |
| 17 | +```javascript |
| 18 | +import * as React from "react"; |
| 19 | + |
| 20 | +export interface SessionContextProps { |
| 21 | + login: string; |
| 22 | + updateLogin: value => void; |
| 23 | +} |
| 24 | + |
| 25 | +export const createDefaultUser = (): SessionContextProps => ({ |
| 26 | + login: "no user", |
| 27 | + updateLogin: value => { |
| 28 | + console.warn( |
| 29 | + "if you are reading this, likely you forgot to add the provider on top of your app" |
| 30 | + ); |
| 31 | + } |
| 32 | +}); |
| 33 | + |
| 34 | +export const SessionContext = |
| 35 | + React.createContext < SessionContextProps > createDefaultUser(); |
| 36 | +``` |
| 37 | + |
| 38 | +- This session context will expose a _provider_ (it will serve us to set the login name in the context), and a _consumer_ (that will let us consume the login name from the context at any point of the application). |
| 39 | + We will create a component (we will name it _SessionProvider_) that on one hand will store in the state the login name and bind it to the _SessionContext_ and on the other hand it will act as a wrapper (usually it will sit on top of the application and wrap the application). |
| 40 | + |
| 41 | +_./src/common/sessionContext.tsx_ |
| 42 | + |
| 43 | +Append this to the bottom of the file. |
| 44 | + |
| 45 | +```typescript |
| 46 | +export const SessionProvider: React.StatelessComponent = props => { |
| 47 | + const [login, setLogin] = React.useState<string>(""); |
| 48 | + |
| 49 | + return ( |
| 50 | + <SessionContext.Provider value={{ login, updateLogin: setLogin }}> |
| 51 | + {props.children} |
| 52 | + </SessionContext.Provider> |
| 53 | + ); |
| 54 | +}; |
| 55 | +``` |
| 56 | + |
| 57 | +- Let's import the _SessionProvider_ in the barrel _index_. |
| 58 | + |
| 59 | +_./src/common/index.ts_ |
| 60 | + |
| 61 | +```diff |
| 62 | +export * from "./notification"; |
| 63 | +export * from "./textFieldForm"; |
| 64 | ++ export * from "./sessionContext"; |
| 65 | +``` |
| 66 | + |
| 67 | +- Let's setup the _sessionProvider_ at the top of our application. |
| 68 | + |
| 69 | +_./src/app.tsx_ |
| 70 | + |
| 71 | +```diff |
| 72 | +import * as React from "react"; |
| 73 | +import { HashRouter, Switch, Route } from "react-router-dom"; |
| 74 | +import { LoginPage } from "./pages/loginPage"; |
| 75 | +import { PageB } from "./pages/pageB"; |
| 76 | ++ import { SessionProvider } from "./common"; |
| 77 | + |
| 78 | +export const App = () => { |
| 79 | + return ( |
| 80 | + <> |
| 81 | ++ <SessionProvider> |
| 82 | + <HashRouter> |
| 83 | + <Switch> |
| 84 | + <Route exact={true} path="/" component={LoginPage} /> |
| 85 | + <Route path="/pageB" component={PageB} /> |
| 86 | + </Switch> |
| 87 | + </HashRouter> |
| 88 | ++ </SessionProvider> |
| 89 | + </> |
| 90 | + ); |
| 91 | +}; |
| 92 | + |
| 93 | +``` |
| 94 | + |
| 95 | +- Let's access the context in PageB using the _useContext_. |
| 96 | + |
| 97 | +_./src/pages/pageB.tsx_ |
| 98 | + |
| 99 | +```diff |
| 100 | +import * as React from "react"; |
| 101 | +import { Link } from "react-router-dom"; |
| 102 | ++ import { SessionContext } from '../common'; |
| 103 | + |
| 104 | +- export const PageB = () => ( |
| 105 | ++ export const PageB = () => { |
| 106 | ++ |
| 107 | ++ const loginContext = React.useContext(SessionContext); |
| 108 | ++ |
| 109 | ++ return ( |
| 110 | + <div> |
| 111 | + <h2>Hello from page B</h2> |
| 112 | ++ <h3>User logged in: {loginContext.login}</h3> |
| 113 | + <br /> |
| 114 | + <Link to="/">Navigate to Login</Link> |
| 115 | + </div> |
| 116 | ++ ) |
| 117 | ++} |
| 118 | +``` |
| 119 | + |
| 120 | +- Let's update the loginPage. |
| 121 | + |
| 122 | +_./src/pages/loginPage.tsx_ |
| 123 | + |
| 124 | +```diff |
| 125 | ++ import { TextFieldForm } from "../common"; |
| 126 | +import { TextFieldForm, SessionContext } from "../common"; |
| 127 | + |
| 128 | +``` |
| 129 | + |
| 130 | +_./src/pages/loginPage.tsx_ |
| 131 | + |
| 132 | +```diff |
| 133 | +const LoginPageInner = (props: Props) => { |
| 134 | ++ const loginContext = React.useContext(SessionContext); |
| 135 | + |
| 136 | + const [loginInfo, setLoginInfo] = React.useState<LoginEntity>( |
| 137 | + createEmptyLogin() |
| 138 | + ); |
| 139 | + const [loginFormErrors, setLoginFormErrors] = React.useState<LoginFormErrors>( |
| 140 | + createDefaultLoginFormErrors() |
| 141 | + ); |
| 142 | + const [showLoginFailedMsg, setShowLoginFailedMsg] = React.useState(false); |
| 143 | + const { classes } = props; |
| 144 | + |
| 145 | + const onLogin = () => { |
| 146 | + loginFormValidation.validateForm(loginInfo).then(formValidationResult => { |
| 147 | + if (formValidationResult.succeeded) { |
| 148 | + if (isValidLogin(loginInfo)) { |
| 149 | + props.history.push("/pageB"); |
| 150 | ++ loginContext.updateLogin(loginInfo.login); |
| 151 | + } else { |
| 152 | + setShowLoginFailedMsg(true); |
| 153 | + } |
| 154 | + } else { |
| 155 | + alert("error, review the fields"); |
| 156 | + const updatedLoginFormErrors = { |
| 157 | + ...loginFormErrors, |
| 158 | + ...formValidationResult.fieldErrors |
| 159 | + }; |
| 160 | + setLoginFormErrors(updatedLoginFormErrors); |
| 161 | + } |
| 162 | + }); |
| 163 | + }; |
| 164 | +``` |
| 165 | + |
| 166 | +- Let's give a try. |
| 167 | + |
| 168 | +# About Basefactor + Lemoncode |
| 169 | + |
| 170 | +We are an innovating team of Javascript experts, passionate about turning your ideas into robust products. |
| 171 | + |
| 172 | +[Basefactor, consultancy by Lemoncode](http://www.basefactor.com) provides consultancy and coaching services. |
| 173 | + |
| 174 | +[Lemoncode](http://lemoncode.net/services/en/#en-home) provides training services. |
| 175 | + |
| 176 | +For the LATAM/Spanish audience we are running an Online Front End Master degree, more info: http://lemoncode.net/master-frontend |
0 commit comments