This note is based on the React document. The React version is 15.4.0.
1. Install
1.1 try
You can try it out by going to codePen before you start, or you can download the HTML file and edit it to try React.
1.2 Creat React Apptool
You are advised to use the Creat React App to quickly create a React single-page application.
npm install -g create-react-app
create-react-app hello-world
cd hello-world
npm start
Copy the code
1.3 Recommended Workflow
Although React can be used without any build tools, in a production environment you should use a build kit to use React for your project. A modern (front-end) workflow typically consists of three parts:
- Package manager: Such as Yarn or Npm makes it easier to use third-party libraries instead of building your own wheels
- Compilers: Such as Babel, which translate code using the latest syntax into a browser compatible version
- Packagers: Such as Webpack or Browserify, allow you to write various styles of modular code that can be packaged and compressed by them
Based on the workflow above, you can install React into your project via Npm or Yarn, compile JSX and ES6 syntax using Babel, and use Webpack or Browserify to package and compress the code for production.
1.4 the CDN service
<! -- Development environment -->
<script src="https://unpkg.com/react@15/dist/react.js"></script>
<script src="https://unpkg.com/react-dom@15/dist/react-dom.js"></script>
<! -- Production environment -->
<script src="https://unpkg.com/react@15/dist/react.min.js"></script>
<script src="https://unpkg.com/react-dom@15/dist/react-dom.min.js"></script>
Copy the code
2. Hello World
A basic example of React:
ReactDom.render(
<h1>Hello world!</h1>.document.getElementById('root'))Copy the code
You can try modifying this code on CodePen to see what happens.
React recommends using it with ES6 syntax, but only if you know () => {}, const, let, ‘template literals’, and classes
3. JSX person
const element = <h1>hello world</h1>
Copy the code
The code above, which is neither a string nor HTML (essentially
Hello world
), is JSX. The official recommendation is to use JSX with it, which is fully functional JavaScript as opposed to the template language. JSX is used to create the React element.
3.1 JSX is an expression
Like other JavaScript expressions, JSX is an expression. The React compiled JSX returns normal JavaScript objects, which means you can treat a JSX statement like a normal JavaScript expression: Assign it to a variable, use it as a function argument, return value, and so on:
function getGreating (user) {
if (user) {
return <h1>hello {formatName(user)}!</h1>
}
return <h1>hello world!</h1>
}
Copy the code
To dig a little deeper, Babel will convert JSX to a call to react.createlement (), so the following two are completely equivalent:
// JSX
const mine = (
<h1 className="greeting">That's my title</h1>
)
// javaScript
const yours = react.creatElement(
'h1',
{ className: 'greeting ' },
'Here's your title.'
)
Copy the code
However, react.createElement() returns an object similar to the following:
const element = {
type: 'h1'.props: {
className: 'greeting'.children: 'Whose title is this?'
}
// ...
}
Copy the code
It’s not hard to see how JSX can be used — like a javaScript expression.
3.2 Embedding JavaScript expressions in JSX
With curly braces {}, you can embed any JavaScript expression in JSX:
const element = (
<h1>
Hello, {formatName(user)}!
</h1>
);
Copy the code
We can use indentation and line breaks on JSX for readability, but to avoid JavaScript’s auto-semicolon mechanism, we should add a pair of parentheses around the JSX for line breaks.
It is safe to insert user input into JSX elements. React escapes text inside elements by default to prevent XSS attacks.
3.3 Declare attributes in JSX
Like declaring element attributes in HTML, you can declare attributes directly on the React element. When you want the attribute value to be a variable or reference, it’s like embedding a JavaScript expression in JSX, using curly braces {} to insert the value of the “React element.”
// Simple attribute values
const element = <div tabIndex="0"></div>;
// Attribute values are variables or references
const element = <img src={user.avatarUrl}></img>;
Copy the code
Note that JSX uses camelCase for element attribute names. In addition, on React built-in elements, attributes such as class and for need to be replaced with className and htmlFor (custom elements can be used normally).
3.4 Declare child elements in JSX
If the React element has no child elements within its tag, you can use a single tag as in XML (including the HTML elements built into React).
const element = <img src={user.avatarUrl} />;
Copy the code
If there are child elements, wrap them directly within the parent element as in HTML (note the parentheses () for newline JSX) :
const element = (
<div>
<h1>Hello!</h1>
<h2>Good to see you here.</h2>
</div>
)
Copy the code
4. Render elements
The React element is the smallest component of the React application. The element describes the interface. Unlike browser DOM elements, React elements are simple objects. Creating them requires far less performance than creating real DOM elements. The React DOM is responsible for matching React elements to real DOM elements:
const ele = <h1>Hello World!</h1>
Copy the code
The React element is not confused with the React component. The React element is a component of the React component. A React component consists of one or more React elements. The React element is a configuration object that tells React how to render a page and which DOM elements to use. The React element is not the same as the DOM element.
4.1 Render the React element into the DOM
Create a React element and render it to an element in the DOM with reactdom.render () (that’s it) :
const ele = <h1>Hello World!</h1>
ReactDOM.render(
ele,
document.getElementById('root') // Suppose there is an element with id root on the page
)
Copy the code
4.2 Update rendered elements
Remember that the React element is immutable, and once created, you can no longer directly change its attributes or child elements. If we wanted to update the React element in the element rendered to root above, we would have to refresh it frame by frame like a movie film without any other means:
function tick() {
const element = (
<div>
<h1>Hello World!</h1>
<p>{new Date().toLocaleTimeString()}</p>
</div>
)
ReactDOM.render(
ele,
document.getElementById('root') // Suppose there is an element with id root on the page
)
}
setInterval(tick, 1000) // Refresh every second
Copy the code
Of course we wouldn’t normally do this, but this is a good example of another problem — what does React do when rendering a page? The answer is that it only renders different parts of the DOM from the last time it rendered! React will compare the current render to the last render in the DOM and only refresh those!
[Image upload failed…(image-89394-1535353259915)]
5. The components andprops
(Input attributes)
Components allow you to split the UI into separate reusable pieces that have separate scopes and don’t interfere with each other. You can think of a component as a function-like concept. The component takes arguments from its props property and returns the React element to describe the UI.
5.1 Using functions and classes (class
) Define components
The simplest way to define a component is to write a constructor:
function Welcom (props) {
return <h1>hello, {props.name}</h1>
}
Copy the code
The Welcom constructor above is a valid React component because it takes an object as an argument and returns the React element. We call such a component a “functional” component because it is a JavaScript constructor. You can also use ES6’s class feature to define functions:
class Welcom extends React.Component {
render () {
return <h1>hello, {this.props.name}</h1>}}Copy the code
The ES6 class feature is a syntactic sugar of the ES5 constructors and object inheritance features, which can be converted to ES5. React recommends this method for simplicity because it’s easier to write and more readable. But the point of this approach is to inherit some core properties from react.component. more on that later. For the moment, though, we’ll just create components with simple functions.
5.2 Rendering Components
The React element can be used not only to specify the DOM element to be used, but also to refer to custom components:
// Refers to the DOM element you want to use
constConst ele2 = <Welcom name="Sara">Copy the code
When React encounters a custom component like
, it puts the JSX properties (the React element properties) in an object (that object is props) and passes them to the component’s constructor, which in turn returns the React element for rendering.
5.3 Component Combination
Since the React element can be used to refer to custom components, components can be nested with each other:
function Welcom (props) {
return <h1>Hello, {props.name}</h1>
}
function WelcomList () {
return (
<div>
<Welcom name="Sara" />
<Welcom name="Lily" />
<Welcom name="Tom" />
</div>
)
}
function App () {
return <WelcomList />
}
ReactDOM.render(
<App />,
document.getElementById('root')
)
Copy the code
5.4 Component Extraction
Since components can be nested and combined, we can split a large component into many smaller components. React officially encourages cutting up the UI into different components for implementation. React elements should be extracted into components in the following ways:
- This set of elements is used elsewhere
- The internal functionality of this set of elements is relatively complex
This part is actually a componentized idea, which I won’t go into here.
5.5 read-onlyprops
Similar to the concept of “pure functions” (which do not change any external values, including input parameters, that is, completely decoupled from the outside), a component should not modify its props, whether it is defined using constructors or classes, because these are the parameters that are input to the component. React is strictly qualified at this point:
All React components must act like “pure functions” that never modify their own
props
attribute
6. state
(Private state) and life cycle
Let’s use the clock example above to understand the private state and life cycle of a component.
function tick() {
const element = (
<div>
<h1>Hello World!</h1>
<p>{new Date().toLocaleTimeString()}</p>
</div>
)
ReactDOM.render(
ele,
document.getElementById('root') // Suppose there is an element with id root on the page
)
}
setInterval(tick, 1000)
Copy the code
First we extract the clock as a component:
// Clock component
function Clock(props) {
return (
<div>
<h1>Hello World!</h1>
<p>{props.date.toLocaleTimeString()}</p>
</div>)}// re-render
function tick () {
ReactDOM.render(
<Clock date={new Date()} / >, document.getelementById ('root') // Suppose there is an element with id root on the page)} // Refresh setInterval(tick, 1000)Copy the code
We found that for the Clock component, the refresh time function has nothing to do with the outside. It does not involve any external variables and can be realized by the Clock component itself instead of letting the outside pass the time to it. The Clock component needs a “private state” to do this.
6.1 fromReact.Component
On the inheritance
So far, we used a simple constructor to create the React components, whether external input attribute or private state, we need to manually create all and management, such as modified private state after a refresh rendering, external input attribute is read-only such function, if we don’t have in the constructor manually implementation does not exist.
Here we can inherit some useful methods from the react.component.react built-in constructor, which includes “private state” and “lifecycle” implementations. We can use the ES6 class feature to implement this inheritance (this is not necessary, of course, it is possible to use ES5 constructors and prototypes, but that would be much more cumbersome and less readable) :
class Clock extends React.Component {
render () { // React provides hook functions for rendering and refreshing components
return (
<div>
<h1>Hello, world!</h1>
<h2>It is {this.props.date.toLocaleTimeString()}.</h2>
</div>)}}Copy the code
6.2 Defining component Private States
React.componentprovides props and state to access external input properties and internal private state, respectively. We can access the private state through state in the clock component, initialize the private state in its constructor, and render it to the page:
class Clock extends React.Component {
constructor (props) {
super(props) // The constructor function of a class in ES6 can access its parent's constructor via super
this.state = { date: new Date()}}// Note that ES6 does not require any symbols between classes' methods
render () {
return (
<div>
<h1>Hello, world!</h1>
<h2>It is {this.state.date.toLocaleTimeString()}.</h2>
</div>
)
}
}
ReactDOM.render(
<Clock />Document.getelementbyid ('root '))Copy the code
Note that in the constructor constructor of the Clock class, the parent class’s constructor is called for full inheritance. You should always perform this step when creating a React component using the Class feature.
6.3 Adding life Cycle Functions
React provides a series of “lifecycle hooks” for calling back functions at various stages of a component, from its creation to its rendering to its destruction. To enable the Clock component to refresh itself, we want to add a timer to refresh every second as soon as the component is created and destroy the timer when the component is destroyed, so we need to use two lifecycle hook functions:
componentDidMount
: Executes after the component is rendered to the pagecomponentWillUnmount
: Executed before the component is destroyed
class Clock extends React.Component {
constructor (props) {
super(props) // The constructor function of a class in ES6 can access its parent's constructor via super
this.state = { date: new Date()}}// Note that ES6 does not require any symbols between classes' methods
render () {
return (
<div>
<h1>Hello, world!</h1>
<h2>It is {this.state.date.toLocaleTimeString()}.</h2>
</div>
)
}
componentDidMount () {
this.timerID = setInterval(this.tick.bind(this), 1000)
}
componentWillUnmount() {
clearInterval(this.timerID)
}
}
ReactDOM.render(
<Clock />Document.getelementbyid ('root '))Copy the code
Note that we stored the timer on the component instance, not in state, but as a rule: any variable that is not used in the render() function of the component should not be stored in state
Then add the tick method. The setState() method tells React that the state has changed, and React calls the component’s Render() method to refresh the DOM. This is why it is said that any variable not used in the render() function of a component should not be stored in state:
class Clock extends React.Component {
constructor (props) {
super(props) // The constructor function of a class in ES6 can access its parent's constructor via super
this.state = { date: new Date()}}// Note that ES6 does not require any symbols between classes' methods
render () {
return (
<div>
<h1>Hello, world!</h1>
<h2>It is {this.state.date.toLocaleTimeString()}.</h2>
</div>
)
}
componentDidMount () {
this.timerID = setInterval(this.tick, 1000)
}
componentWillUnmount() {
clearInterval(this.timerID)
}
tick () {
this.setState({ date: new Date()})// This method triggers the React call to the render method of the instance for redrawing
}
}
ReactDOM.render(
<Clock />Document.getelementbyid ('root '))Copy the code
6.4 Component Life cycle Summary
-
- When passing a component to
ReactDOM.render()
The React function calls the component’s constructorconstructor
Do some initialization
- When passing a component to
-
- And React is going to call it
Clock
The component’srender()
Method to render the component
- And React is going to call it
-
- React is called when the component is rendered
componentDidMount()
Lifecycle hook functions
- React is called when the component is rendered
-
- when
setState()
React will re-invoke the component when the function is calledrender()
Method to redraw
- when
-
- React is called when a component is removed from the DOM
componentWillUnmount()
Lifecycle hook functions
- React is called when a component is removed from the DOM
6.5 setState
Matters needing attention
- Don’t change directly
state
Direct to componentstate
Attribute assignments in the React file will not trigger DOM updates because React doesn’t know about themstate
Has been changed state
The update of theReact processes multiple pairs at oncesetState
Call to improve performance, so callsetState()
Should not be directly based on something else fromstate
orprops
React does not refresh the DOM when other values used for the calculation change again (because it is not called again)setState()
). To fix this, React provides another callsetState()
Function approach: Pass in a function instead of an object
// This is not the case
this.setState({
counter: this.state.counter + this.props.increment
})
// Correct usage
this.setState((prevState, props) = > ({ // Takes an argument representing the previous state and an argument for the current props
counter: prevState.counter + props.increment // This actually returns an object, which is shorthand for the ES6 arrow function
}))
Copy the code
setState
Is a merge of objects rather than a replacementsetState
The method combines the passed parameter object or the returned object of the function with the existing onestate
Object to merge, very similar to usingObject.assign(prevState, newState)
The effect of
6.6 Single Data Flow
In the React component nesting, the parent component passes data to the child component via props. Whether the data is passed in from the parent component’s props, state, or somewhere else, the child component doesn’t know and doesn’t care because it can’t modify the data passed in via props, only read it. In this way, data can be passed in from the outermost parent, but not the other way around.
This is known as “top-down” or “unidirectional” data flow: each component can modify only its own and its children’s data, but not its parent’s. Redux is one of the best known libraries for managing data and state, but as applications get more complex, multiple components may need to share some data or state.
7. Events
7.1 Basic Usage
Binding events in React is very similar to binding events directly in HTML. Define an event handler and bind it in JSX:
function Greeting () {
function sayHi(e) {
e.preventDefault()
console.log('Hi! ')}return (
<a onClick={sayHi}>Click me to say hi!</a>)}Copy the code
All event binding attributes such as onClick are written in camelCase. The value of the event binding attribute is not a string but the name of the event handler, which can be passed with () and omitted () if there is no parameter.
7.2 Event handlers when defining components using classesthis
Pointing problem of
When defining components using ES6’s Class feature, it is common to write event handlers as if they were methods of the class. But notice the method’s this pointer.
The default this for a method defined in a class refers to an instance of the current class, but the event handler loses the reference to this because it is bound to a specific element. If your handler uses the this keyword to refer to the current component instance, you need to manually bind this to the current component instance. There are three ways to do this:
1) Called from class constructor or from JSXFunction.prototype.bind()
Manual binding
class Toggle extends React.Component { constructor(props) { super(props); this.state = {isToggleOn: true}; this.handleClick = this.handleClick.bind(this); } handleClick() {// console.log(this) this.setState(prevState => ({isToggleOn:! prevState.isToggleOn })); } render() {return (// <button onClick={this.handleclick.bind (this)}> {this.state.isToggleOn ? 'ON' : 'OFF'} </button> ); } } ReactDOM.render( <Toggle />, document.getElementById('content') );Copy the code
2) Wrap an arrow function around the event handler in the event binding property of JSX and return the result of the handler call
render() {
return (
<button onClick={(e)= >This.handleclick (e)}> //</button>
);
}
Copy the code
3) Babel provides an experimental notation for ES8+
class LoggingButton extends React.Component {
handleClick = (a)= > { // For purely experimental writing, Babel is required
console.log('this is:'.this);
}
render() {
return (
<button onClick={this.handleClick}>
Click me
</button>); }}Copy the code
7.3 Event Objects
React is an event object provided by React. The React event object is compatible with browsers and retains the interface of standard event objects. See the React website for more information. The concern is how event objects are used in event handlers.
In JSX of event binding, handlers accept a parameter named event to represent the event object. Event can be considered as a reserved word in the event binding interpolation. If you need to pass more parameters to the event handler, use another identifier.
In addition, the different event bindings written in Section 7.2 handle event objects slightly differently, mainly in event binding JSX:
<button onClick={this.handleclick (event)}> Click me </button onClick={this.handleclick (event)} </button> bind() <button onClick={this.handleclick. bind(this, event)}> Click me </button>Copy the code
- When the handlers in the event binding interpolation are omitted
(a)
By default, the handler accepts an argument representing the event object, - When the handler function in the event binding interpolation is not omitted
(a)
, the reserved word needs to be used explicitlyevent
To pass in the event object, or otherwiseundefined
;Pay attention, whether or notconstructor
In the bindingthis
, directly after the handler function name(a)
Causes the function to be executed immediately upon page initialization, possibly with unexpected errors, such as not being calledsetState()
Methods, etc., so it is strongly not recommended to write this way - When the handler function in the event binding interpolation is called
bind()
The reserved word can be used explicitlyevent
To pass in the event object, otherwise React will be inbind()
By default, an argument representing the event object is appended to the end of the function argument sequence
Finally, React does not prevent the default event by returning false. Instead, it explicitly calls event.preventDefault() in the event handler.
8. Conditional rendering
All JavaScript conditional statements can be used for React conditional rendering because JSX is essentially a JavaScript extension language. There are three common conditional renderings based on this:
if... else...
function UserGreeting () {
return <h1>Welcom back!</h1>
}
function GuestGreeting () {
return <h1>Please Sign up.</h1>
}
function App (props) {
if(! props.isLoggedIn) {return <GuestGreeting />
}
return <UserGreeting />
}
ReactDOM.render(
<App isLoggedIn={false} />,
document.getElementById('root')
)
Copy the code
- Ternary operator
function App (props) {
return props.isLoggedIn ? <UserGreeting /> : <GuestGreeting />
}
Copy the code
- A short circuit
function App (props) {
return props.isLoggedIn && <UserGreeting />// if isLoggedIn is true, display UserGreeting; otherwise, no explicit}Copy the code
If the judgment logic is too complex to be written in teradic or short-circuit expressions, and the result of the judgment needs to be used directly in JSX (JSX can only insert expressions through {}, not statements), then use if… else… The statement determines and saves the result to a variable, and then returns the variable or interpolates it into JSX via {} :
function UserGreeting () {
return <h1>Welcom back!</h1>
}
function GuestGreeting () {
return <h1>Please Sign up.</h1>
}
function Button (props) {
return <button onClick={ props.handleToggle} >toggle me</button>
}
class App extends React.Component {
constructor (props) {
super(props)
this.state = {
prevState: false
}
}
handleClick () {
this.setState(prevState= > ({ isLoggedIn: !prevState.isLoggedIn }))
}
render () {
let greeting = this.state.isLoggedIn ? <UserGreeting /> : <GuestGreeting /> return (<div>< div><Button handleToggle={this.handleclick.bind (this)} /></div> greeting } </div> ) } } ReactDOM.render( <App isLoggedIn={false} />, document.getElementById('root') )Copy the code
In addition, returning a false value in the render function of a component prevents the component from rendering, which, combined with conditional judgment, can be used to hide or show the component.
9. List andkey
(index)
9.1 Rendering List
You can render a list like this:
class List extends React.Component { constructor (props) { super(props) } render () { let list = This.number.map(number => (// props <li>{number}</li>)) return (<ul>{list}</ul>)}} reactdom.render (< list) number={[1, 2, 3, 4, 5]} />, document.getElementById('root') )Copy the code
It is also possible to inline the map() call to JSX with {} :
class List extends React.Component {
constructor (props) {
super(props)
}
render () {
return (
<ul>{this.props.number.map(number => (// inline map() method<li key={number}>{number}</li>))}</ul>)}}Copy the code
You typically use the map() method of an array to assemble a list from an array, similar to how you assemble HTML with JavaScript. But the code above runs with a warning:
9.2 key
React’s difference comparison algorithm requires a unique key within the scope of the list to improve performance when rendering lists (often used to tell which list item has changed). This unique key needs to be provided manually. React officially recommends using unique identification fields in list data as render keys for list items. If there is none, you can use the array index as a placeholder, which may compromise performance.
Let list = this.props.number.map(number => (// props <li key={number.tostring ()}>{number}</li>))Copy the code
Note the following points when using key:
- Can only be specified in an array
key
B: To be precise, only inmap()
Is used in the callback functionkey
key
You need to ensure uniqueness within the scope of the list: in the same arraykey
I want to make sure that it’s unique, but different arrayskey
It doesn’t matterkey
Not asprops
Incoming componentsIt can be considered thatkey
React is the reserved word in JSX. You can’t use it to pass data to components and should use another word instead
Form of 10.
React has a Controlled Component, which refers to form elements Controlled by React. Use the onChange event handler to map the change in the value of a form element to the component’s state, and then interpolate the value of the component to the value of the form element in JSX with {}.
class Form extends React.Component {
constructor (props) {
super(props)
this.state ={
inputTextValue: ' '
}
this.handleInputTextChange = this.handleInputTextChange.bind(this)
}
render () {
return (
<form>
<input
value={this.state.inputTextValue}/ / fromstateBind values to form elementsonChange={this.handleInputTextChange}/>
</form>) } handleInputTextChange (e) { this.setState({ inputTextValue: E.targe. value // map changes in form element values to state})}} reactdom.render (<Form />,
document.getElementById('root')
)
Copy the code
Almost all form elements are used as in the example, “controlling” the element with value, making state the only state store for the component. But sometimes when we use React in non-React projects or for some other reason we don’t want to use controlled components, we can choose the “uncontrolled component” technique, which is not expanded here.
11. The share status is improved
Consider the following requirements: there are two boxes on the page for entering the amount of currency, one in US dollars and one in RMB, along with a prompt such as “We have 1 US dollar, which is 6.9 yuan”. The two input boxes are required to input one randomly, and the other input box will automatically display the amount of currency after conversion according to the exchange rate, and the prompt text below will also follow the change.
Typically, we would write a component for entering the amount of currency, and then put two components on the page:
const exchangeRate = 6.9339
const currency = {
'$': '$'.A '$': Renminbi
}
class CurrencyInput extends React.Component {
constructor (props) {
super(props)
this.state = {
value: ' '
}
this.changeHandler = this.changeHandler.bind(this)
}
render () {
return(<div> <label> {currency[this.props]} : <input value={this.state.value} onChange={this.changeHandler}/> </label> </div> ) } changeHandler (e) { this.setState({ value: e.target.value }) } } class App extends React.Component { constructor (props) { super(props) } render () { return( <div> <CurrencyInput currency={'$'}/> <CurrencyInput currency={'¥'} /> <p> </p> </div>)}} reactdom.render (<App />, document.getelementbyid ('root'))Copy the code
In the code above we pass the currency category to the props input box component, showing the input boxes for dollars and names, respectively. Then inside the input box component, we use the “controlled component” technique from the previous section to hand over the value of the input box to the component’s state control. But the requirements are not fulfilled — the two input fields are not in sync, and the external component does not know what value is being filled into the component so the following prompt statement is not updated.
Many times, several components need to allude to the same changing state. We recommend elevating the shared state to their most recent common ancestor.
As officially recommended, this is where we need to use the shared state promotion technique: we need to promote the “quantity” state shared by the two currency input box components to their nearest ancestor, the App component.
/ /... Omitted code
class CurrencyInput extends React.Component {
constructor (props) {
super(props)
this.handleChange = this.handleChange.bind(this)
}
render () {
return(<div> <label> {CURRENCY[this.props]} : <input Value ={this.props. Value} onChange={this.handlechange}/> // If additional parameters need to be passed, only one more layer </label> </div>)} handleChange (e) { this.props.onValueChange(e.target.value, This.props. Currency) // Class App extends react.currency {constructor (props) {super(props) This. state = {// Store shared state on ancestor element dollar: ", yuan: '} this. ValueChangeHandler = this. ValueChangeHandler. Bind (this)} render () {return (/ / by props down passing Shared state and the callback function, <div> <CurrencyInput value={this.state.dollar} currency={'$'} /> <CurrencyInput value={this.state.yuan} currency={'¥'} OnValueChange ={this.valuechangeHandler}/> <p> We have {this.state.dollar}, ValueChangeHandler (value, type) {this.setState({dollar: type === '$'?) {this.state.yuan} yuan </p> </div>)} valueChangeHandler (value, type) {this.setState({dollar: type === '$'? Value: this. Exchange (value, type), yuan: type === '¥'? value : this.exchange(value, type) }) } exchange (value, type) { return value * (type === '$' ? EXCHANGERATE : 1 / EXCHANGERATE) } } // ... Omitted codeCopy the code
In fact whether the dollar or RMB, actually is only a number, the number represents a certain number of dollars and at the same time a certain number of yuan, so better, we can and should keep only a state on the parent component, then calculate when rendering subcomponents subcomponents state and passed to them:
/ /... Omitted code
function exchange (value, type) { // Put the conversion function globally so that child components can access it
return value * (type === '$' ? EXCHANGERATE : 1 / EXCHANGERATE)
}
class CurrencyInput extends React.Component {
/ /... Omitted code
render () {
// Child components calculate their own state at render time
let currentCurrency = this.props.currentCurrency
let currency = this.props.currency
let value = ' '
if(currentCurrency.value ! = =' '&&!/^\s+$/g.test(currentCurrency.value)) {
value = currentCurrency.type === currency ?
currentCurrency.value :
exchange(currentCurrency.value, currentCurrency.type)
}
return(<div> <label> {CURRENCY[CURRENCY]} : <input value={value} onChange={this.handleChange}/> </label> </div>)}/ /... {constructor (props) {super(props) this. State = {currentCurrency: {function (props); {// Store a value that is currently changed value: "", type: "'}} this. ValueChangeHandler = this. ValueChangeHandler. Bind (this)} render () {/ / pass share the status of the components, At the same time, the status of parent components need your calculated the return (< div > < CurrencyInput currentCurrency = {this. State. CurrentCurrency} currency = {} '$' OnValueChange = {this. ValueChangeHandler} / > < CurrencyInput currentCurrency = {this. State. CurrentCurrency} currency = {} '$' OnValueChange = {this. ValueChangeHandler} / > < p > we have {exchange (enclosing state. CurrentCurrency. Value, '$')} $, That is {exchange (enclosing state. CurrentCurrency. Value, '$')} yuan < / p > < / div >)} valueChangeHandler (value, {this.setState({currentCurrency: $value) {this.setState({currentCurrency: $value); { value, type } }) } } ReactDOM.render( <App />, document.getElementById('root') )Copy the code
The above example is a good example of the React official “single data flow” model that is repeatedly recommended. The benefit of the extra code is that there are fewer bugs caused by child components being able to modify the shared state themselves. After all, when we promote the shared state to the parent component, all changes to the shared state are concentrated on the parent component.
Also, to reiterate the principle that any state that can be computed by state or props should not be placed in state. As in the above example, it should be used directly after calculation in the render() function.
12. Aggregate rather than inherit
React officially recommends using aggregation rather than inheritance to reuse code between components. There are usually two cases of taking. One is that part of the structure or content of the component is uncertain and needs to be imported from the outside. Then the component is equivalent to a container. The other is to create a more concrete component from a more abstract component, such as “shells” and “landing shells”.
12.1 container
When parts of a component need to be passed in externally, you can use a special props property, children. Access props. Children inside the component to get what is written inside the start and end tags of the component when using it:
function FancyBorder(props) {
return (
<div className={'FancyBorder FancyBorder-'+props.color} >
{props.children}
</div>
);
}
function WelcomeDialog() {
return (
<FancyBorder color="blue">
<h1 className="Dialog-title">
Welcome
</h1>
<p className="Dialog-message">
Thank you for visiting our spacecraft!
</p>
</FancyBorder>
);
}
Copy the code
When a component has multiple parts that need to be passed in externally, relying on props. Children alone is not sufficient. Remember that the React component props can accept any type of argument, so you can pass components directly to the props as well:
function SplitPane(props) {
return (
<div className="SplitPane">
<div className="SplitPane-left">
{props.left}
</div>
<div className="SplitPane-right">
{props.right}
</div>
</div>
);
}
function App() { // Insert another JSX with {} in JSX, because JSX is also an expression
return <SplitPane left={ <Contacts /> } right={ <Chat /> } />
}
Copy the code
12.2 realization
Sometimes we want a component to be a special case (more concrete) of another, more abstract component. The official recommendation is to wrap an abstract component in a concrete component and configure it using props:
function Dialog(props) {
return (
<FancyBorder color="blue">
<h1 className="Dialog-title">
{props.title}
</h1>
<p className="Dialog-message">
{props.message}
</p>
</FancyBorder>
);
}
function WelcomeDialog() {
return (
<Dialog
title="Welcome"
message="Thank you for visiting our spacecraft!" />
);
}
Copy the code
As for inheritance… Forget it.
13. Think in React
React officials say React is the best way to build large, high-performance Web applications. It performed very well on Fb and Instagram. The cool thing about React is how it makes you look at your application when building it. Let’s take you through this thought process by writing a search list.
13.1 Start with the effect drawing
Suppose we have a JSON interface, and we have the designer’s renderings for us:
The JSON interface returns data in the following format:
[{category: "Sporting Goods", price: "$49.99", more significantly: true, name: "Football"}, {category: "Sporting Goods", price: "$9.99", more significantly: true, name: "Baseball"}, {category: "Sporting Goods", price: "$29.99", more significantly: false, name: "Basketball"}, {category: "Electronics", price: "$99.99", more significantly: true, name: "iPod Touch"}, {category: "Electronics", price: "$399.99", more significantly: false, name: "iPhone 5"}, {category: "Electronics", price: "$199.99", one: true, name: "Nexus 7"}]Copy the code
13.2 Step 1: Break down the UI by component level
The first thing to do is to box the components (and sub-components) on the rendering and name the components. If your fellow designer gave it to you, he’s probably already done this part of the work. Its PSD layer name will most likely be used as your component name.
But how exactly do you divide components? The answer is the same as if you were creating a function or an object. One of these principles is the “single responsibility principle”, which states that a component should only do one thing, otherwise it should be broken up into more sub-components.
If you regularly present JSON data to your users, you should know that if you create the right data model, your UI (and components) will be well organized. Because your UI and data model share the same information structure, it also means that partitioning components can be tedious. Just split your component into the data structure returned by JSON.
React Is the last chapter of the React basics tutorial. I’ll translate it later.
(Updated on July 27, 2018 at…… Heaven good reincarnation, heaven rao who…… React will be written after a lapse of nearly 2 years. I have to come back to read the article and review it myself. Just fill in the hole!
You will see that there are five components in this simple application. We italicize the data that each component represents.
- FilterableProductTable (orange) : The entire content of the example
- SearchBar (blue): acceptUser input
- ProductTable (green): Displays filtered based on user inputProduct list
- ProductCategoryRow (cyan): for eachcategoryShow a title
- ProductRow (red): for eachproductAccording to a line
The header of ProductTable, which contains the Name and Price tags, is not a separate component. It’s a matter of preference, and it’s debatable either way. In this example, we have left it in ProductTable because ProductTable is responsible for rendering the product list and the header is part of the list. However, when this header gets complicated (for example, when we add sorting capabilities), it makes sense to pull it out as a ProductTableHeader component.
Now that we have identified the components, let’s structure them. It’s very easy. A component that appears inside another component in a rendering and should be structurally a child of the former:
FilterableProductTable
SearchBar
ProductTable
ProductCategoryRow
ProductRow
13.3 Step 2: Build a static version of React
See the sample code in Codepen.
Now that you have the component structure, it’s time to start implementing your application. The easiest way to do this is to build a version that renders the UI with data, but without interaction. It’s best to keep these two steps separate, because building a static version requires mindless writing, while adding interactions requires a lot of thought and a little writing. We’ll see why later.
To build a static version of your application, you will want to reuse other components to build new components and use props to pass data. Props is a way to pass data from a parent component to a child component. If you’re familiar with state, build this static version without using state at all. State is reserved for interactivity, and data changes over time. This is still a static version, so you don’t need it yet.
You can build top-down or bottom-up. That is, you can build from higher-level components (such as FilterableProductTable) or from lower-level components (ProductRow). In simple examples, it’s usually easier to build from the top down, while in larger projects, it’s easier to build components from the bottom up and write tests for them at the same time.
At the end of this step, you will have a reusable component library to render your data. Since your application is currently static, components will only have the Render () method. Components at the top of the component structure (FilterableProductTable) receive your data as a “prop”. If you modify the base data and call reactdom.render () again, the UI will update. It’s easy to see where your UI is updating and changing, because nothing complicated has happened so far. React’s one-way data flow (also known as one-way binding) keeps things organized and fast.
Link to the React documentation for help when performing this step.
Props and State
There are two data models in React: props and state. It’s important to understand the differences between the two models. If you don’t understand the differences, check out the React documentation.
13.4 Step 3: Identify the minimum (but complete) UI state
In order for your UI to be interactive, you need to be able to trigger changes to your underlying data. React uses **state** to make this easy.
To build your application correctly, first you need to think about the minimum set of variable states your application needs. The key here is DRY: Don’t Repeat Yourself. Figure out the minimum state representation your application needs, and then figure out everything else as needed. For example, if you want to build a TODO LIST, you only need to maintain an array of TODO items; There is no need to hold a separate state variable for quantities. Instead, when you want to render the number of ToDos, simply read the length of the TODO item array.
Consider all the data in our sample application:
- Original Product List
- The search text entered by the user
- The value of the check box
- Filtered product list
Let’s go through them one by one to figure out which is state. Simply ask three questions on each data point:
- It is passed from the parent component
props
Was it passed in? If it is, it isn’tstate
- Does it never change? If it is, it isn’t
state
- You can base other components on
state
orprops
Can we figure it out? If it is, it isn’tstate
The original product list was passed in from props, so it’s not state. The search text and check box values entered by the user appear to be state because they vary and cannot be calculated based on other data. Finally, the filtered product list is not state, because it can be calculated based on the original product list, the search text entered by the user, and the value of the check box.
So finally, our state is:
- The search text entered by the user
- The value of the check box
13.5 Step 4: Determine yourstate
The location of the
See the sample code in Codepen.
So now that we have the minimum set of states our application needs, we need to figure out which components to put those states in.
Remember: React is all about single-item data flows along the component hierarchy. It may not be immediately clear at first which component should have which states. This is usually the hardest part for beginners, but you can do it by following these steps:
For each state in your application:
- Determine based on the
state
Render all components - Find a common owner component for these components (find one in the hierarchy that contains all of the required components
state
A single component of the component) - Either a common owner component or a higher-level ancestor component should own this
state
- If you can’t find a proper component to control this
state
Create a parent component on top of the common owner component to control thisstate
Let’s look at our application with this strategy:
ProductTable
Based onstate
To filter the list of products,SearchBar
You need to show the search text and check box status- Their common ownership component is
FilterableProductTable
- So theoretically put the filter text and check box values in
FilterableProductTable
Is more appropriate
Well, we’ve decided to put our state in the FilterableProductTable. First, add an instance attribute this.state = {filterText: “, inStockOnly: false} to the constructor of FilterableProductTable to initialize your application’s state. FilterText and inStockOnly are then passed as props to the ProductTable and SearchBar. Finally, use these props to filter rows of the ProductTable and set the value of the SearchBar.
You can already see some of what your app does: Set filterText to Ball and refresh your app, and you’ll see the data table updated correctly.
13.6 Step 5: Add the reverse Data Flow
See the sample code in Codepen.
So far we have built an application where props and state flow down the hierarchy and render correctly. Now it’s time to support data flow in a different way: form components deep in the hierarchy need to update state on FilterableProductTable.
React makes this data flow very straightforward, giving you a better understanding of how your application works. But it does require a little more code than traditional two-way data binding.
If you try to type or click the check box in the current version of the example, React will ignore your input. This is intentional because we have set the value of the input to always equal the state passed in from FilterableProductTable.
Let’s think about what we want to do. We want to update state to reflect user input whenever the user modifies the form. Because components should only update their own state, FilterableProductTable passes a callback to the SearchBar that is executed when state needs to be updated. We can use the onChange event input to notify it of updates. SetState () is called in callback functions passed in FilterableProductTable and the application is updated.
While this sounds complicated, it’s really only a few lines of code. And it’s pretty clear how your data flows through your application.
13.7 Finally done
Hopefully this article gave you some ideas on how to think about building components and applications with React. While this may be a bit more than your original code, keep in mind that you read code a lot more than you write it, and it’s very easy to read this modular, straightforward code. When you start building large component libraries, you’ll appreciate the clarity and modularity, and you’ll write less and less code as you reuse it. 🙂