You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
We will modify our application to show a different message ("Hello, Stranger.") if the user is not defined. Also, we will show an image for the user from the JSON object.
Components let you split the UI into independent, reusable pieces, and think about each piece in isolation. They accept arbitrary inputs (called "props") and return React elements.
// src/Clock.jsimportReact,{Component}from'react';classClockextendsReact.Component{constructor(props){super(props);// This should always be calledthis.state={date: newDate()};}render(){return(<div><h1>Hello, world!</h1><h2>It is {this.state.date.toLocaleTimeString()}.</h2></div>);}}exportdefaultClock;
The only place where you can assign this.state is the constructor.
The componentDidMount() hook runs after the component output has been rendered to the DOM.
When you call setState(), React merges the object you provide into the current state.
setState() also accepts a function instead of an object where you can access previous state. See documentation.
If the name of key to set is a variable, you can call setState() like below:
this.setState({[key]: value});
While this.props is set up by React itself and this.state has a special meaning, you are free to add additional fields (like this.timerId) to the class manually if you need to store something that is not used for the visual output.
If you don't use something in render(), it shouldn't be in the state.
NOTE: Do NOT set state by calling this.state.date = new Date();. This will not re-render the component.
// src/App.jsclassAppextendsReact.Component{constructor(props){super(props);this.state={number: Math.random()};this.refreshNumber=this.refreshNumber.bind(this);}refreshNumber(){this.setState({number: Math.random()});}render(){return(<div><buttononClick={this.refreshNumber}>Refresh</button><NumberDecoratornumber={this.state.number}/></div>);}}classNumberDecoratorextendsReact.Component{componentWillMount(){console.log('Componet WILL MOUNT!');}componentDidMount(){console.log('Componet DID MOUNT!');}componentWillReceiveProps(newProps){console.log('Componet WILL RECEIVE PROPS!');}shouldComponentUpdate(newProps,newState){returntrue;}componentWillUpdate(newProps,newState){console.log('Componet WILL UPDATE!');}componentDidUpdate(prevProps,prevState){console.log('Componet DID UPDATE!');}componentWillUnmount(){console.log('Componet WILL UNMOUNT!');}render(){return(<p><b>Random number: </b>{this.props.number}</p>);}}
Now, on rendering the page for first time, you will see componentWillMount and componentDidMount getting called.
When you click "Refresh" button, it will generate a new random number and pass it to NumberDecorator, and the hooks componentWillReceiveProps, componentWillUpdate, and componentDidUpdate will be called in order.
Now, lets add code to unmount the App component after 5 seconds.
// src/Toggle.jsimportReactfrom'react';classToggleextendsReact.Component{constructor(props){super(props);this.handleClick=this.handleClick.bind(this);}handleClick(e){console.log('The link was clicked.');console.log(this);}render(){return(<ahref='#'onClick={this.handleClick}>
Click me
</a>);}}exportdefaultToggle;
You have to be careful about the meaning of this inside JSX callbacks. In JavaScript, class methods are not bound by default. If you forget to bind this.handleClick and pass it to onClick, this will be undefined when the function is actually called.
Another way to define this callback for onClick can be:
<ahref='#'onClick={()=>this.handleClick()}>
And if the callback function contains only one statement, you can do:
When using React you should generally not need to call addEventListener to add listeners to a DOM element after it is created. Instead, just provide a listener when the element is initially rendered.
Keys help React identify which items in the list have changed, are added, or are removed. Keys should be given to the elements inside the array to give the elements a stable identity.
If you don't set a key for each list item, you will see below warning in the browser console:
Warning: Each child in an array or iterator should have a unique "key" prop.
Some components don't know their children ahead of time. Such components should use the special children prop to pass children elements directly into their output:
Our third component Topics is a bit complex as it contains topics and links to each one of them.
// src/AppRouter.jsconstTopics=({match})=>(<div><h2>Topics</h2><ul><li><Linkto={`${match.url}/rendering`}>
Rendering with React
</Link></li><li><Linkto={`${match.url}/components`}>
Components
</Link></li><li><Linkto={`${match.url}/props-v-state`}>
Props v State
</Link></li></ul><Routepath={`${match.url}/:topicId`}component={Topic}/><Routeexactpath={match.url}render={()=>(<h3>Please select a topic.</h3>)}/></div>)constTopic=({match})=>(<div><h3>{match.params.topicId}</h3></div>)
Note, how we can do interpolation using ${} and define dynamic components of a route using colon (:) e.g. :topicId.
Also, instead of specifying the component in call to Route, we can directly pass the content to render like we did for when no topic is selected.
Say, we have some protected paths which can be accessed only after user logs in to his account. Then, we can define a common component for all such paths which will redirect the user to 'login' path if he is not authenticated.
<Router><ProtectedRoutepath='/protected'component={ProtectedView}/></Router>constProtectedRoute=({component: Component, ...rest})=>(<Route{...rest}render={(props)=>(// call `Route` with `render` and all props for `ProtectedRoute` other than `component` propauth.isAuthenticated ? (<Component{...props}/>// If user is authenticated, render component given in props) : (<Redirectto={{// Else redirect user to login pathpathname: '/login',state: {from: props.location}}}/>))}/>)
constAuthButton=withRouter(({ history })=>(auth.isAuthenticated ? (<p>
Welcome Jagdeep Singh! // If user is logged in, show a message and a "Sign out" button
<buttononClick={()=>{auth.signout();// Signs out the userhistory.push('/');// Pushes path '/' into browser history}}>Sign out</button></p>) : (<p>You are not logged in.</p>)));
See a detailed example of Redirects and auths here.
A <Route> with no path always matches. So, it should be placed last in the list.
<Router><div><ul><li><Linkto='/'>Home</Link></li><li><Linkto='/old-match'>Old Match, to be redirected</Link></li><li><Linkto='/will-match'>Will Match</Link></li><li><Linkto='/will-not-match'>Will Not Match</Link></li><li><Linkto='/also/will/not/match'>Also Will Not Match</Link></li></ul><Switch><Routepath='/'exactcomponent={Home}/> // This will match for home path '/'
<Redirectfrom='/old-match'to='/will-match'/> // Will redirect to '/will-match' from '/old-match'
<Routepath='/will-match'component={WillMatch}/> // Will match path '/will-match'
<Routecomponent={NoMatch}/> // Will match all other paths e.g. '/will-not-match'
</Switch></div></Router>
To change something in the state, you need to dispatch an action. An action is a plain JavaScript object. Here are a few example actions:
{type: 'ADD_TODO',text: 'Go to swimming pool'}{type: 'TOGGLE_TODO',index: 1}{type: 'SET_VISIBILITY_FILTER',filter: 'SHOW_ALL'}
Actions must have a type property that indicates the type of action being performed. Types should typically be defined as string constants.
Action creators
Action creators simply return an action.
functionaddTodo(text){return{type: ADD_TODO,
text
}}
This makes them portable and easy to test.
To actually initiate a dispatch, pass the result to the dispatch() function: dispatch(addTodo(text)).
Alternatively, you can create a bound action creator that automatically dispatches:
constboundAddTodo=text=>dispatch(addTodo(text))
The dispatch() function can be accessed directly from the store as store.dispatch().
10.1.3 reducer
Finally, to tie state and actions together, we write a function called a reducer. It’s just a function that takes state and action as arguments, and returns the next state of the app.
(previousState,action)=>newState
It would be hard to write such a function for a big app, so we write smaller functions managing parts of the state:
Redux provides a utility called combineReducers() that does the same boilerplate logic that the todoApp above currently does. With its help, we can rewrite todoApp like this:
import{combineReducers}from'redux'consttodoApp=combineReducers({
visibilityFilter,
todos
})
Things you should never do inside a reducer:
Mutate its arguments
Perform side effects like API calls and routing transitions
Call non-pure functions, e.g. Date.now() or Math.random()
To summarize:
The whole state of your app is stored in an object tree inside a single store.
The only way to change the state tree is to emit an action, an object describing what happened.
To specify how the actions transform the state tree, you write pure reducers.
Technically, a container component is just a React component that uses store.subscribe() to read a part of the Redux state tree and supply props to a presentational component it renders. To generate a container component using connect(), you need to define a special function called mapStateToProps that tells how to transform the current Redux store state into the props you want to pass to a presentational component you are wrapping.
In addition to reading the state, container components can dispatch actions. In a similar fashion, you can define a function called mapDispatchToProps() that receives the dispatch() method and returns callback props that you want to inject into the presentational component.
All container components need access to the Redux store so they can subscribe to it. We recommend using a special React Redux component called <Provider> to magically make the store available to all container components in the application without passing it explicitly.