This is the owner's own React learning notes, all descriptions are the owner's own understanding, not necessarily the correct description, please check as appropriate, if you can point out the error will be appreciated.
1. Event handling
Binding Method
<button onClick={activateLasers}> Activate Lasers </button>
When using React, add a listener when the element is initially rendered, as in the case of toggling the switch button:
class Toggle extends React.Component { constructor(props) { super(props); this.state = {isToggleOn: true}; // This binding is essential in order to use `this'in callbacks this.handleClick = this.handleClick.bind(this); } handleClick() { this.setState(state => ({ isToggleOn: !state.isToggleOn })); } render() { return ( <button onClick={this.handleClick}> {this.state.isToggleOn ? 'ON' : 'OFF'} </button> ); } } ReactDOM.render( <Toggle />, document.getElementById('root') );
Since javascript's class method does not bind this by default, manually bind this yourself
There are several other uses for binding
class LoggingButton extends React.Component { handleClick() { console.log('this is:', this); } render() { // This syntax ensures that `this` within `handleClick` is bound. return ( <button onClick={() => this.handleClick()}> Click me </button> ); } }
This syntax creates different callback functions each time the LoggingButton is rendered, and these components are rendered extra when prop is passed in as a subcomponent, so it is not recommended.
The following are the class fields syntax implementations:
class LoggingButton extends React.Component { // This syntax ensures that `this` within `handleClick` is bound. // Note: This is * experimental * grammar. handleClick = () => { console.log('this is:', this); } render() { return ( <button onClick={this.handleClick}> Click me </button> ); } }
Styles for passing parameters to events
<button onClick={(e) => this.deleteRow(id, e)}>Delete Row</button> <button onClick={this.deleteRow.bind(this, id)}>Delete Row</button>
The above two methods are equivalent, the way the arrow function is used, the event object must be passed; the bind way, the event object is passed implicitly.
2. Conditional Rendering
Write two components and then decide which component to display or not based on the value passed from props
Examples are as follows:
class LoginControl extends React.Component { constructor(props) { super(props); this.handleLoginClick = this.handleLoginClick.bind(this); this.handleLogoutClick = this.handleLogoutClick.bind(this); this.state = {isLoggedIn: false}; } handleLoginClick() { this.setState({isLoggedIn: true}); } handleLogoutClick() { this.setState({isLoggedIn: false}); } render() { const isLoggedIn = this.state.isLoggedIn; let button; if (isLoggedIn) { button = <LogoutButton onClick={this.handleLogoutClick} />; } else { button = <LoginButton onClick={this.handleLoginClick} />; } return ( <div> <Greeting isLoggedIn={isLoggedIn} /> {button} </div> ); } } ReactDOM.render( <LoginControl />, document.getElementById('root') );
The &&or trinomial operator can also be used to determine the rendering component on an expression.
3. Lists and Key
DOM elements that can be looped through map functions such as <li>.
function NumberList(props) { const numbers = props.numbers; const listItems = numbers.map((number) => <li key={number.toString()}> {number} </li> ); return ( <ul>{listItems}</ul> ); } const numbers = [1, 2, 3, 4, 5]; ReactDOM.render( <NumberList numbers={numbers} />, document.getElementById('root') );
When creating multiple components using a map loop, a key is required to help React identify which elements have been modified or deleted.
The key should be placed on the component created by the loop, not on the native DOM tag within the component.
function ListItem(props) { // Correct! You don't need to specify key here: return <li>{props.value}</li>; } function NumberList(props) { const numbers = props.numbers; const listItems = numbers.map((number) => // Correct! The key should be specified in the context of the array <ListItem key={number.toString()} value={number} /> ); return ( <ul> {listItems} </ul> ); } const numbers = [1, 2, 3, 4, 5]; ReactDOM.render( <NumberList numbers={numbers} />, document.getElementById('root') );
That is, key is required in the map() method.
4. Forms
Controlled Components
In HTML, form elements such as <input>, <textarea>, and <select> usually maintain the state themselves and update it based on user input. In React, mutable state is usually saved in the component's state property and can only be used by using setState() To update.
We can combine the two to make React's state the "only data source". The React component that renders the form also controls what happens to the form during user input. Form input elements that React controls in this way are called "controlled components".
For example:
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 of submission: ' + 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> ); } }
textarea tag
In React, <textarea> uses the value attribute instead. This makes the form that uses <textarea> very similar to the form that uses the single line input:
class EssayForm extends React.Component { constructor(props) { super(props); this.state = { value: 'Write a story about what you like DOM Element articles.' }; this.handleChange = this.handleChange.bind(this); this.handleSubmit = this.handleSubmit.bind(this); } handleChange(event) { this.setState({value: event.target.value}); } handleSubmit(event) { alert('Submitted articles: ' + this.state.value); event.preventDefault(); } render() { return ( <form onSubmit={this.handleSubmit}> <label> Article: <textarea value={this.state.value} onChange={this.handleChange} /> </label> <input type="submit" value="Submit" /> </form> ); } }
this.state.value is initialized in the constructor, so the text area defaults to an initial value.
select tag
React does not use the selected attribute, but instead uses the value attribute on the root select tag. This is more convenient in controlled components because you only need to update it in the root tag. For example:
class FlavorForm extends React.Component { constructor(props) { super(props); this.state = {value: 'coconut'}; this.handleChange = this.handleChange.bind(this); this.handleSubmit = this.handleSubmit.bind(this); } handleChange(event) { this.setState({value: event.target.value}); } handleSubmit(event) { alert('Your favorite flavor is: ' + this.state.value); event.preventDefault(); } render() { return ( <form onSubmit={this.handleSubmit}> <label> Choose your favorite flavor: <select value={this.state.value} onChange={this.handleChange}> <option value="grapefruit">Grapefruit</option> <option value="lime">Lime</option> <option value="coconut">Coconut</option> <option value="mango">Mango</option> </select> </label> <input type="submit" value="Submit" /> </form> ); } }
Processing multiple inputs
When more than one input element needs to be processed, we can add a name attribute to each element and let the processing function choose the operation to perform based on the value of event.target.name.
class Reservation extends React.Component { constructor(props) { super(props); this.state = { isGoing: true, numberOfGuests: 2 }; this.handleInputChange = this.handleInputChange.bind(this); } handleInputChange(event) { const target = event.target; const value = target.name === 'isGoing' ? target.checked : target.value; const name = target.name; this.setState({ [name]: value }); } render() { return ( <form> <label> participate in: <input name="isGoing" type="checkbox" checked={this.state.isGoing} onChange={this.handleInputChange} /> </label> <br /> <label> Number of guests: <input name="numberOfGuests" type="number" value={this.state.numberOfGuests} onChange={this.handleInputChange} /> </label> </form> ); } }
Where [name]:value uses ES6 syntax equivalent to ES5
var partialState = {}; partialState[name] = value; this.setState(partialState);
Controlled Input Null Value
The following code demonstrates this. (Inputs are initially locked but become editable after a short delay.)
ReactDOM.render(<input value="hi" />, mountNode); setTimeout(function() { ReactDOM.render(<input value={null} />, mountNode); }, 1000);
Uncontrolled components
To write an uncontrolled component instead of a data processing function for each status update, you can use ref to get form data from the DOM node.
For example, the following code accepts a form's value using an uncontrolled component:
class NameForm extends React.Component { constructor(props) { super(props); this.handleSubmit = this.handleSubmit.bind(this); this.input = React.createRef(); } handleSubmit(event) { alert('A name was submitted: ' + this.input.current.value); event.preventDefault(); } render() { return ( <form onSubmit={this.handleSubmit}> <label> Name: <input type="text" ref={this.input} /> </label> <input type="submit" value="Submit" /> </form> ); } }
Default value
In uncontrolled components, if you want to use React to give the component an initial value and then not control subsequent updates, you can specify a defaultValue property instead of a value. Updating the value of the defaultValue property after a component has been mounted will not cause any updates to the value on the DOM.
render() { return ( <form onSubmit={this.handleSubmit}> <label> Name: <input defaultValue="Bob" type="text" ref={this.input} /> </label> <input type="submit" value="Submit" /> </form> ); }
Similarly, <input type="checkbox"> and <input type="radio"> support defaultChecked, <select> and <textarea> support defaultValue.
File Input
In React, <input type="file" /> is always a non-controlled component because its value can only be set by the user, not by code.
You can use the File API to interact with files. The following example shows how to create a ref of a DOM node to get information about files when submitting a form.
class FileInput extends React.Component { constructor(props) { super(props); this.handleSubmit = this.handleSubmit.bind(this); this.fileInput = React.createRef(); } handleSubmit(event) { event.preventDefault(); alert( `Selected file - ${this.fileInput.current.files[0].name}` ); } render() { return ( <form onSubmit={this.handleSubmit}> <label> Upload file: <input type="file" ref={this.fileInput} /> </label> <br /> <button type="submit">Submit</button> </form> ); } } ReactDOM.render( <FileInput />, document.getElementById('root') );