This is the notes taken while learning React.
[TOC]
React State setState() async Source:
https://zh-hans.reactjs.org/docs/state-and-lifecycle.html
http://huziketang.mangojuice.top/books/react/lesson10
React will not change state immediately after setState().
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 class Button extends React .Component { constructor ( ) { super () this .state = { count : 0 } } handleClickOnButton () { console .log(this .state.count) this .setState({ count: this .state.count + 1 }) this .setState({ count: this .state.count + 2 }) console .log(this .state.count) } render () { return ( <button onClick={this .handleClickOnButton.bind(this )}> {this .state.count} </button> ) } } ReactDOM.render( <Button />, document .getElementById('root' ) );
If we want to use the state changed before, we can use function in setState()
1 2 3 4 5 6 ... handleClickOnButton () { this .setState(state => ({ count : state.count + 1 })) this .setState(state => ({ count : state.count + 2 })) } ...
Count will increase by 3 every time.
Props Validation source:
https://www.runoob.com/react/react-props.html
https://zh-hans.reactjs.org/docs/typechecking-with-proptypes.html
If we don’t validate props in React 16, ESLint will report errors.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 var title = "runoob" ;class MyTitle extends React .Component { render ( ) { return ( <h1>Hello, {this .props.title}</h1> ); } } MyTitle.propTypes = { title: PropTypes.string }; ReactDOM.render( <MyTitle title={title} />, document .getElementById('example' ) );
More types:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 import PropTypes from 'prop-types' ;MyComponent.propTypes = { optionalArray: PropTypes.array, optionalBool: PropTypes.bool, optionalFunc: PropTypes.func, optionalNumber: PropTypes.number, optionalObject: PropTypes.object, optionalString: PropTypes.string, optionalSymbol: PropTypes.symbol, optionalNode: PropTypes.node, optionalElement: PropTypes.element, optionalElementType: PropTypes.elementType, optionalMessage: PropTypes.instanceOf(Message), optionalEnum: PropTypes.oneOf(['News' , 'Photos' ]), optionalUnion: PropTypes.oneOfType([ PropTypes.string, PropTypes.number, PropTypes.instanceOf(Message) ]), optionalArrayOf: PropTypes.arrayOf(PropTypes.number), optionalObjectOf: PropTypes.objectOf(PropTypes.number), optionalObjectWithShape: PropTypes.shape({ color: PropTypes.string, fontSize: PropTypes.number }), optionalObjectWithStrictShape: PropTypes.exact({ name: PropTypes.string, quantity: PropTypes.number }), requiredFunc: PropTypes.func.isRequired, requiredAny: PropTypes.any.isRequired, customProp: function (props, propName, componentName ) { if (!/matchme/ .test(props[propName])) { return new Error ( 'Invalid prop `' + propName + '` supplied to' + ' `' + componentName + '`. Validation failed.' ); } }, customArrayProp: PropTypes.arrayOf(function (propValue, key, componentName, location, propFullName ) { if (!/matchme/ .test(propValue[key])) { return new Error ( 'Invalid prop `' + propFullName + '` supplied to' + ' `' + componentName + '`. Validation failed.' ); } }) };
https://reactjs.org/docs/forms.html
we can store input value in state
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 class NameForm extends React .Component { constructor (props ) { super (props); this .state = {value : '' }; this .handleChange = this .handleChange.bind(this ); this .handleSubmit = this .handleSubmit.bind(this ); } handleChange (event ) { this .setState({value : event.target.value}); } handleSubmit (event ) { alert('name submitted: ' + this .state.value); event.preventDefault(); } render ( ) { return ( <form onSubmit={this .handleSubmit}> <label> Name: <input type="text" value={this .state.value} onChange={this .handleChange} /> </label> <input type="submit" value="Submit" /> </form> ); }
JSX Repeat elements with empty array.map()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 const Rating: FunctionComponent<Props> = ({ value, number, color } ) => { const starNum: number = Math .floor(value); const starFrac: number = value - starNum; return ( <div className="rating" > <span> {Array .apply(null , Array (starNum)).map(i => ( <i style={{ color }} className="fas fa-star" /> ))} <i style={{ color }} className={ starFrac >= 0.5 ? 'fas fa-star-half-alt' : 'far fa-star' } /> </span> </div> ); };
another example for rendering a list of item:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 function App ( ) { const ll = ["0" , "10" , "20" , "30" , "40" , "50" , "60" , "70" , "80" , "90" , "100" ]; const llItems = ll.map((item ) => ( <div className="m-t-20" id={`my-progress-box-${item} ` } key={item}> <div className="d-flex no-block align-items-center" > <span>{item}%</span> </div> <div className="progress" > <div className={`progress-bar progress-bar-striped ${item >= 40 ? "bg-green" : "bg-red" } ` } role="progressbar" style={{width : `${item} %` }} aria-valuenow="10" aria-valuemin="0" aria-valuemax="100" /> </div> </div>)); return ( <div className="App" > <div style={{width : "200px" }}> {llItems} </div> <button onClick={() => clickButton()}> Save </button> </div> ); }
Condition rendering Ref:
https://zh-hans.reactjs.org/docs/conditional-rendering.html
https://stackoverflow.com/questions/35762351/correct-way-to-handle-conditional-styling-in-react
#1. Use className tag 1 2 <div className={`progress-bar progress-bar-striped ${item >= 40 ? "bg-green" : "bg-red" } ` } role="progressbar" style={{width : `${item} %` }} aria-valuenow="10" aria-valuemin="0" aria-valuemax="100" />
#2. Use style tag 1 2 3 4 5 6 7 8 9 style={{ textDecoration: completed ? 'line-through' : 'none' }} style={{ textDecoration: completed && 'line-through' }}
#3. Use function/component 1 2 3 4 5 6 7 8 9 10 11 12 13 function Greeting (props ) { const isLoggedIn = props.isLoggedIn; if (isLoggedIn) { return <UserGreeting /> ; } return <GuestGreeting /> ; } ReactDOM.render( <Greeting isLoggedIn={false } />, document .getElementById('root' ) );
React Router Package 1 2 npm install react-router-dom npm install react-router
Basic Structure Source:
https://reactrouter.com/web/guides/quick-start
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 <Router> <div> <nav> <ul> <li> <Link to="/" >Home</Link> </li> <li> <Link to="/about" >About</Link> </li> <li> <Link to="/users" >Users</Link> </li> </ul> </nav> { } <Switch> <Route path="/about" > <About /> </Route> <Route path="/users" > <Users /> </Route> <Route path="/" > <Home /> </Route> </Switch> </div> </Router>
withRouter we can use withRouter to redirect to another page using this.props.history.push('/page');
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 import React from "react" ;import PropTypes from "prop-types" ;import { withRouter } from "react-router" ;class Home extends React .Component { static propTypes = { history: PropTypes.object.isRequired }; handleSubmit (e ) { this .props.inputSize(this .state.size); e.preventDefault(); this .props.history.push('/game' ); console .log(this .state.size); } render ( ) { return ( <form onSubmit={this .handleSubmit}> <label className="label" > Rows: <input className="input" type="text" value={this .state.size[0 ]} onChange={this .handleRowChange} /> </label> <label className="label" > Columns: <input className="input" type="text" value={this .state.size[1 ]} onChange={this .handleColumnChange} /> </label> <input type="submit" value="Submit" /> </form> ) } } export default connect(mapStateToProps, { inputSize })(withRouter(Home));