Contents:
- create custom React components
- compose UI using generic DOM components as well as your own custom ones
- set properties
- maintain state
2个方法建react component:
- Use function -- return the UI
- Use ES6 class that extends React.Component
Using created component
- ReactDOM.render() -- put a react component at specified location
ReactDOM.render(component, domWhere);
Function Component
- Use normal JS class
// JS component class
const MyComponent = function() {
return React.createElement('span', null, 'I am so custom');
};
// render
ReactDOM.render(
MyComponent(),
document.getElementById('app')
);
- Or use JSX
// JSX component
const MyComponent = function() {
return <span>I am so custom</span>;
};
// render
ReactDOM.render(
<MyComponent />,
document.getElementById('app')
);
Using props
- In function decl: function(props)
- In component: {props.prop_name}
- In render: <comp_name prop_name = val />
Alternatively,
- In function decl: function({prop_1, prop_2, ...})
- In component: {prop_1}, {prop_2}, ...
- In render: <comp_name prop_1 = val, ... />
Set default prop
comp_name.defaultProps = {
prop_name: 'default_value',
};
Class Component
// JS class extending React.Component
class MyComponent extends React.Component {
render() {
return React.createElement('span', null, 'I am so custom');
// or with JSX:
// return <span>I am so custom</span>;
}
}
- Can return JSX or regular JS
- It doesn't matter which syntax you use, both can be rendered with JSX syntax:
ReactDOM.render(
<MyComponent />,
document.getElementById('app')
);
Using props
- In component class: {this.props.prop_name}
- this.props is read-only
- In render: <comp_name prop_name = val />
Set defult prop
comp_name.defaultProps = {
prop_name: 'default_value',
};
set prop type
prop type: types of props your component expects
- wrong type results in error
** npm i prop-types
// importing at the beginning
import PropTypes from 'prop-types';
...
// outside component
[component].propTypes = {
[prop_name]: PropTypes.arrayOf(PropTypes.string), //array of strings
[prop_name]: PropTypes.arrayOf(PropTypes.arrayOf(PropTypes.string)), //array of array of strings
};
Using component from outside
- render then reference from outside
// render
const myTextAreaCounter = ReactDOM.render( ... );
// reference
const reactAppNode = ReactDOM.findDOMNode(myTextAreaCounter);
Component States
- All components have States.
- State refers to any dynamic data in the component.
- When state changes, React rebuilds the UI in the DOM automatically
Access state
this.state
- Read-only! Except in constructor.
Update state
this.setState()
- setState internally calls reactDOM.render to update UI
- Argument:
- state object {state_name: state_val}
- object is then merged into the component state object
Stateless Component example
class TextAreaCounter extends React.Component {
render() {
const text = this.props.text;
return (
<div>
<textarea defaultValue={text}/>
<h3>{text.length}</h3>
</div>
);
}
}
TextAreaCounter.defaultProps = {
text: 'Count me as I type',
};
- 1 prop called text
- 1 attribute length
- Default value 'Count me as I type'
Stateful Component example
- Class constructor is the only place this.state = ... is allowed
- call super() before using this in constructor
- Update JSX to include event handler
- value = {text}
- onChange={....}
- Now the <textarea> UI component is managed by react (because of onChange)
class TextAreaCounter extends React.Component {
constructor() {
super();
this.state = {};
}
render() {
const text = 'text' in this.state ? this.state.text : this.props.text;
return (
<div>
<textarea
value={text}
onChange={event => this.onTextChange(event)}
/>
<h3>{text.length}</h3>
</div>
);
}
}
Update State:
- Include a new method in component class
- Called every time user changes <textarea>
- set 'text' prop to a new state
onTextChange(event) {
this.setState({
text: event.target.value,
});
}
Prop vs. State
- this.props is like a collection of all the arguments passed to a class constructor, while this.state is a bag of your private properties.
- input initialization data can be props, latter in the component data change should be states
// In render
<Component initialData={data} />
// In component constructor
this.state = {data: props.initialData};
- initial data is passed in as prop
- in constructor set the data as initial state
Event Handling
- Option 1: Use arrow function -- in render()
onChange={event => this.onTextChange(event)}
- Option 2: Bind the listener method -- in render()
onChange={this.onTextChange.bind(this)}
- Option 3: Common pattern -- in constructor
constructor{
this.onTextChange = this.onTextChange.bind(this);
}
render(){
<... onChange={onChange={this.onTextChange}}>
}
bind all the event-handling methods in the constructor;
- Option 4: Function as class property
class TextAreaCounter extends React.Component {
constructor() {
// ...
}
onTextChange = (event) => {
// ...
};
}
Getting event target property
- event.target -- is the target DOM object, where the event happens
- event.target.prop_name -- to access a property of the DOM object
Sorting event example
- Register listener: <thead onClick={this.sort}>
- Bind this.sort in the constructor: this.sort = this.sort.bind(this);
- Implement sort() inside component